aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF')
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp313
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.h100
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DIERef.cpp39
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DIERef.h146
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.cpp141
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h79
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp3862
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h516
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp66
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h81
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.cpp136
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h130
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp108
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h48
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.cpp152
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.h85
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp593
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h145
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.cpp34
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h38
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp176
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h70
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp104
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h57
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp260
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h89
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp662
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h191
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacro.cpp128
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacro.h62
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp56
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h34
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp89
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h110
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp37
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.h25
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp647
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h99
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp128
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h122
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.cpp25
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h45
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp1088
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h377
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp504
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h133
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp38
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h37
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp740
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h183
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp151
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.h94
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp4484
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h565
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp1596
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h398
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp180
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h98
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFProperties.td8
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp87
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h107
61 files changed, 20896 insertions, 0 deletions
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp
new file mode 100644
index 000000000000..1703597a7cd2
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp
@@ -0,0 +1,313 @@
+//===-- AppleDWARFIndex.cpp -----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/SymbolFile/DWARF/AppleDWARFIndex.h"
+#include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h"
+#include "Plugins/SymbolFile/DWARF/DWARFUnit.h"
+#include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h"
+
+#include "lldb/Core/Module.h"
+#include "lldb/Symbol/Function.h"
+#include "llvm/Support/DJB.h"
+
+using namespace lldb_private;
+using namespace lldb;
+using namespace lldb_private::dwarf;
+using namespace lldb_private::plugin::dwarf;
+
+std::unique_ptr<AppleDWARFIndex> AppleDWARFIndex::Create(
+ Module &module, DWARFDataExtractor apple_names,
+ DWARFDataExtractor apple_namespaces, DWARFDataExtractor apple_types,
+ DWARFDataExtractor apple_objc, DWARFDataExtractor debug_str) {
+
+ llvm::DataExtractor llvm_debug_str = debug_str.GetAsLLVM();
+
+ auto apple_names_table_up = std::make_unique<llvm::AppleAcceleratorTable>(
+ apple_names.GetAsLLVMDWARF(), llvm_debug_str);
+
+ auto apple_namespaces_table_up =
+ std::make_unique<llvm::AppleAcceleratorTable>(
+ apple_namespaces.GetAsLLVMDWARF(), llvm_debug_str);
+
+ auto apple_types_table_up = std::make_unique<llvm::AppleAcceleratorTable>(
+ apple_types.GetAsLLVMDWARF(), llvm_debug_str);
+
+ auto apple_objc_table_up = std::make_unique<llvm::AppleAcceleratorTable>(
+ apple_objc.GetAsLLVMDWARF(), llvm_debug_str);
+
+ auto extract_and_check = [](auto &TablePtr) {
+ if (auto E = TablePtr->extract()) {
+ llvm::consumeError(std::move(E));
+ TablePtr.reset();
+ }
+ };
+
+ extract_and_check(apple_names_table_up);
+ extract_and_check(apple_namespaces_table_up);
+ extract_and_check(apple_types_table_up);
+ extract_and_check(apple_objc_table_up);
+ assert(apple_names.GetByteSize() == 0 || apple_names.GetSharedDataBuffer());
+ assert(apple_namespaces.GetByteSize() == 0 ||
+ apple_namespaces.GetSharedDataBuffer());
+ assert(apple_types.GetByteSize() == 0 || apple_types.GetSharedDataBuffer());
+ assert(apple_objc.GetByteSize() == 0 || apple_objc.GetSharedDataBuffer());
+
+ if (apple_names_table_up || apple_namespaces_table_up ||
+ apple_types_table_up || apple_objc_table_up)
+ return std::make_unique<AppleDWARFIndex>(
+ module, std::move(apple_names_table_up),
+ std::move(apple_namespaces_table_up), std::move(apple_types_table_up),
+ std::move(apple_objc_table_up), apple_names.GetSharedDataBuffer(),
+ apple_namespaces.GetSharedDataBuffer(),
+ apple_types.GetSharedDataBuffer(), apple_objc.GetSharedDataBuffer());
+
+ return nullptr;
+}
+
+/// Returns true if `tag` is a class_type of structure_type tag.
+static bool IsClassOrStruct(dw_tag_t tag) {
+ return tag == DW_TAG_class_type || tag == DW_TAG_structure_type;
+}
+
+/// Returns true if `entry` has an extractable DW_ATOM_qual_name_hash and it
+/// matches `expected_hash`.
+static bool
+EntryHasMatchingQualhash(const llvm::AppleAcceleratorTable::Entry &entry,
+ uint32_t expected_hash) {
+ std::optional<llvm::DWARFFormValue> form_value =
+ entry.lookup(dwarf::DW_ATOM_qual_name_hash);
+ if (!form_value)
+ return false;
+ std::optional<uint64_t> hash = form_value->getAsUnsignedConstant();
+ return hash && (*hash == expected_hash);
+}
+
+/// Returns true if `entry` has an extractable DW_ATOM_die_tag and it matches
+/// `expected_tag`. We also consider it a match if the tags are different but
+/// in the set of {TAG_class_type, TAG_struct_type}.
+static bool EntryHasMatchingTag(const llvm::AppleAcceleratorTable::Entry &entry,
+ dw_tag_t expected_tag) {
+ std::optional<llvm::DWARFFormValue> form_value =
+ entry.lookup(dwarf::DW_ATOM_die_tag);
+ if (!form_value)
+ return false;
+ std::optional<uint64_t> maybe_tag = form_value->getAsUnsignedConstant();
+ if (!maybe_tag)
+ return false;
+ auto tag = static_cast<dw_tag_t>(*maybe_tag);
+ return tag == expected_tag ||
+ (IsClassOrStruct(tag) && IsClassOrStruct(expected_tag));
+}
+
+/// Returns true if `entry` has an extractable DW_ATOM_type_flags and the flag
+/// "DW_FLAG_type_implementation" is set.
+static bool
+HasImplementationFlag(const llvm::AppleAcceleratorTable::Entry &entry) {
+ std::optional<llvm::DWARFFormValue> form_value =
+ entry.lookup(dwarf::DW_ATOM_type_flags);
+ if (!form_value)
+ return false;
+ std::optional<uint64_t> Flags = form_value->getAsUnsignedConstant();
+ return Flags &&
+ (*Flags & llvm::dwarf::AcceleratorTable::DW_FLAG_type_implementation);
+}
+
+void AppleDWARFIndex::SearchFor(const llvm::AppleAcceleratorTable &table,
+ llvm::StringRef name,
+ llvm::function_ref<bool(DWARFDIE die)> callback,
+ std::optional<dw_tag_t> search_for_tag,
+ std::optional<uint32_t> search_for_qualhash) {
+ auto converted_cb = DIERefCallback(callback, name);
+ for (const auto &entry : table.equal_range(name)) {
+ if (search_for_qualhash &&
+ !EntryHasMatchingQualhash(entry, *search_for_qualhash))
+ continue;
+ if (search_for_tag && !EntryHasMatchingTag(entry, *search_for_tag))
+ continue;
+ if (!converted_cb(entry))
+ break;
+ }
+}
+
+void AppleDWARFIndex::GetGlobalVariables(
+ ConstString basename, llvm::function_ref<bool(DWARFDIE die)> callback) {
+ if (!m_apple_names_up)
+ return;
+ SearchFor(*m_apple_names_up, basename, callback);
+}
+
+void AppleDWARFIndex::GetGlobalVariables(
+ const RegularExpression &regex,
+ llvm::function_ref<bool(DWARFDIE die)> callback) {
+ if (!m_apple_names_up)
+ return;
+
+ DIERefCallbackImpl converted_cb = DIERefCallback(callback, regex.GetText());
+
+ for (const auto &entry : m_apple_names_up->entries())
+ if (std::optional<llvm::StringRef> name = entry.readName();
+ name && Mangled(*name).NameMatches(regex))
+ if (!converted_cb(entry.BaseEntry))
+ return;
+}
+
+void AppleDWARFIndex::GetGlobalVariables(
+ DWARFUnit &cu, llvm::function_ref<bool(DWARFDIE die)> callback) {
+ if (!m_apple_names_up)
+ return;
+
+ const DWARFUnit &non_skeleton_cu = cu.GetNonSkeletonUnit();
+ dw_offset_t lower_bound = non_skeleton_cu.GetOffset();
+ dw_offset_t upper_bound = non_skeleton_cu.GetNextUnitOffset();
+ auto is_in_range = [lower_bound, upper_bound](std::optional<uint32_t> val) {
+ return val.has_value() && *val >= lower_bound && *val < upper_bound;
+ };
+
+ DIERefCallbackImpl converted_cb = DIERefCallback(callback);
+ for (auto entry : m_apple_names_up->entries()) {
+ if (is_in_range(entry.BaseEntry.getDIESectionOffset()))
+ if (!converted_cb(entry.BaseEntry))
+ return;
+ }
+}
+
+void AppleDWARFIndex::GetObjCMethods(
+ ConstString class_name, llvm::function_ref<bool(DWARFDIE die)> callback) {
+ if (!m_apple_objc_up)
+ return;
+ SearchFor(*m_apple_objc_up, class_name, callback);
+}
+
+void AppleDWARFIndex::GetCompleteObjCClass(
+ ConstString class_name, bool must_be_implementation,
+ llvm::function_ref<bool(DWARFDIE die)> callback) {
+ if (!m_apple_types_up)
+ return;
+
+ llvm::SmallVector<DIERef> decl_dies;
+ auto converted_cb = DIERefCallback(callback, class_name);
+
+ for (const auto &entry : m_apple_types_up->equal_range(class_name)) {
+ if (HasImplementationFlag(entry)) {
+ converted_cb(entry);
+ return;
+ }
+
+ decl_dies.emplace_back(std::nullopt, DIERef::Section::DebugInfo,
+ *entry.getDIESectionOffset());
+ }
+
+ if (must_be_implementation)
+ return;
+ for (DIERef ref : decl_dies)
+ if (!converted_cb(ref))
+ return;
+}
+
+void AppleDWARFIndex::GetTypes(
+ ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
+ if (!m_apple_types_up)
+ return;
+ SearchFor(*m_apple_types_up, name, callback);
+}
+
+void AppleDWARFIndex::GetTypes(
+ const DWARFDeclContext &context,
+ llvm::function_ref<bool(DWARFDIE die)> callback) {
+ if (!m_apple_types_up)
+ return;
+
+ Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups);
+ const bool entries_have_tag =
+ m_apple_types_up->containsAtomType(DW_ATOM_die_tag);
+ const bool entries_have_qual_hash =
+ m_apple_types_up->containsAtomType(DW_ATOM_qual_name_hash);
+
+ llvm::StringRef expected_name = context[0].name;
+
+ if (entries_have_tag && entries_have_qual_hash) {
+ const dw_tag_t expected_tag = context[0].tag;
+ const uint32_t expected_qualname_hash =
+ llvm::djbHash(context.GetQualifiedName());
+ if (log)
+ m_module.LogMessage(log, "FindByNameAndTagAndQualifiedNameHash()");
+ SearchFor(*m_apple_types_up, expected_name, callback, expected_tag,
+ expected_qualname_hash);
+ return;
+ }
+
+ // Historically, if there are no tags, we also ignore qual_hash (why?)
+ if (!entries_have_tag) {
+ SearchFor(*m_apple_names_up, expected_name, callback);
+ return;
+ }
+
+ // We have a tag but no qual hash.
+
+ // When searching for a scoped type (for example,
+ // "std::vector<int>::const_iterator") searching for the innermost
+ // name alone ("const_iterator") could yield many false
+ // positives. By searching for the parent type ("vector<int>")
+ // first we can avoid extracting type DIEs from object files that
+ // would fail the filter anyway.
+ if ((context.GetSize() > 1) && IsClassOrStruct(context[1].tag))
+ if (m_apple_types_up->equal_range(context[1].name).empty())
+ return;
+
+ if (log)
+ m_module.LogMessage(log, "FindByNameAndTag()");
+ const dw_tag_t expected_tag = context[0].tag;
+ SearchFor(*m_apple_types_up, expected_name, callback, expected_tag);
+ return;
+}
+
+void AppleDWARFIndex::GetNamespaces(
+ ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
+ if (!m_apple_namespaces_up)
+ return;
+ SearchFor(*m_apple_namespaces_up, name, callback);
+}
+
+void AppleDWARFIndex::GetFunctions(
+ const Module::LookupInfo &lookup_info, SymbolFileDWARF &dwarf,
+ const CompilerDeclContext &parent_decl_ctx,
+ llvm::function_ref<bool(DWARFDIE die)> callback) {
+ if (!m_apple_names_up)
+ return;
+
+ ConstString name = lookup_info.GetLookupName();
+ for (const auto &entry : m_apple_names_up->equal_range(name)) {
+ DIERef die_ref(std::nullopt, DIERef::Section::DebugInfo,
+ *entry.getDIESectionOffset());
+ DWARFDIE die = dwarf.GetDIE(die_ref);
+ if (!die) {
+ ReportInvalidDIERef(die_ref, name);
+ continue;
+ }
+ if (!ProcessFunctionDIE(lookup_info, die, parent_decl_ctx, callback))
+ return;
+ }
+}
+
+void AppleDWARFIndex::GetFunctions(
+ const RegularExpression &regex,
+ llvm::function_ref<bool(DWARFDIE die)> callback) {
+ return GetGlobalVariables(regex, callback);
+}
+
+void AppleDWARFIndex::Dump(Stream &s) {
+ if (m_apple_names_up)
+ s.PutCString(".apple_names index present\n");
+ if (m_apple_namespaces_up)
+ s.PutCString(".apple_namespaces index present\n");
+ if (m_apple_types_up)
+ s.PutCString(".apple_types index present\n");
+ if (m_apple_objc_up)
+ s.PutCString(".apple_objc index present\n");
+ // TODO: Dump index contents
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.h
new file mode 100644
index 000000000000..73de75b583bd
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.h
@@ -0,0 +1,100 @@
+//===-- AppleDWARFIndex.h --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_APPLEDWARFINDEX_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_APPLEDWARFINDEX_H
+
+#include "Plugins/SymbolFile/DWARF/DWARFIndex.h"
+#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
+
+namespace lldb_private::plugin {
+namespace dwarf {
+class AppleDWARFIndex : public DWARFIndex {
+public:
+ static std::unique_ptr<AppleDWARFIndex>
+ Create(Module &module, DWARFDataExtractor apple_names,
+ DWARFDataExtractor apple_namespaces, DWARFDataExtractor apple_types,
+ DWARFDataExtractor apple_objc, DWARFDataExtractor debug_str);
+
+ AppleDWARFIndex(Module &module,
+ std::unique_ptr<llvm::AppleAcceleratorTable> apple_names,
+ std::unique_ptr<llvm::AppleAcceleratorTable> apple_namespaces,
+ std::unique_ptr<llvm::AppleAcceleratorTable> apple_types,
+ std::unique_ptr<llvm::AppleAcceleratorTable> apple_objc,
+ lldb::DataBufferSP apple_names_storage,
+ lldb::DataBufferSP apple_namespaces_storage,
+ lldb::DataBufferSP apple_types_storage,
+ lldb::DataBufferSP apple_objc_storage)
+ : DWARFIndex(module), m_apple_names_up(std::move(apple_names)),
+ m_apple_namespaces_up(std::move(apple_namespaces)),
+ m_apple_types_up(std::move(apple_types)),
+ m_apple_objc_up(std::move(apple_objc)),
+ m_apple_names_storage(apple_names_storage),
+ m_apple_namespaces_storage(apple_namespaces_storage),
+ m_apple_types_storage(apple_types_storage),
+ m_apple_objc_storage(apple_objc_storage) {}
+
+ void Preload() override {}
+
+ void
+ GetGlobalVariables(ConstString basename,
+ llvm::function_ref<bool(DWARFDIE die)> callback) override;
+ void
+ GetGlobalVariables(const RegularExpression &regex,
+ llvm::function_ref<bool(DWARFDIE die)> callback) override;
+ void
+ GetGlobalVariables(DWARFUnit &cu,
+ llvm::function_ref<bool(DWARFDIE die)> callback) override;
+ void GetObjCMethods(ConstString class_name,
+ llvm::function_ref<bool(DWARFDIE die)> callback) override;
+ void GetCompleteObjCClass(
+ ConstString class_name, bool must_be_implementation,
+ llvm::function_ref<bool(DWARFDIE die)> callback) override;
+ void GetTypes(ConstString name,
+ llvm::function_ref<bool(DWARFDIE die)> callback) override;
+ void GetTypes(const DWARFDeclContext &context,
+ llvm::function_ref<bool(DWARFDIE die)> callback) override;
+ void GetNamespaces(ConstString name,
+ llvm::function_ref<bool(DWARFDIE die)> callback) override;
+ void GetFunctions(const Module::LookupInfo &lookup_info,
+ SymbolFileDWARF &dwarf,
+ const CompilerDeclContext &parent_decl_ctx,
+ llvm::function_ref<bool(DWARFDIE die)> callback) override;
+ void GetFunctions(const RegularExpression &regex,
+ llvm::function_ref<bool(DWARFDIE die)> callback) override;
+
+ void Dump(Stream &s) override;
+
+private:
+ std::unique_ptr<llvm::AppleAcceleratorTable> m_apple_names_up;
+ std::unique_ptr<llvm::AppleAcceleratorTable> m_apple_namespaces_up;
+ std::unique_ptr<llvm::AppleAcceleratorTable> m_apple_types_up;
+ std::unique_ptr<llvm::AppleAcceleratorTable> m_apple_objc_up;
+ /// The following storage variables hold the data that the apple accelerator
+ /// tables tables above point to.
+ /// {
+ lldb::DataBufferSP m_apple_names_storage;
+ lldb::DataBufferSP m_apple_namespaces_storage;
+ lldb::DataBufferSP m_apple_types_storage;
+ lldb::DataBufferSP m_apple_objc_storage;
+ /// }
+
+ /// Search for entries whose name is `name` in `table`, calling `callback` for
+ /// each match. If `search_for_tag` is provided, ignore entries whose tag is
+ /// not `search_for_tag`. If `search_for_qualhash` is provided, ignore entries
+ /// whose qualified name hash does not match `search_for_qualhash`.
+ /// If `callback` returns false for an entry, the search is interrupted.
+ void SearchFor(const llvm::AppleAcceleratorTable &table, llvm::StringRef name,
+ llvm::function_ref<bool(DWARFDIE die)> callback,
+ std::optional<dw_tag_t> search_for_tag = std::nullopt,
+ std::optional<uint32_t> search_for_qualhash = std::nullopt);
+};
+} // namespace dwarf
+} // namespace lldb_private::plugin
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_APPLEDWARFINDEX_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DIERef.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DIERef.cpp
new file mode 100644
index 000000000000..163e9f4c081c
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DIERef.cpp
@@ -0,0 +1,39 @@
+//===-- DIERef.cpp --------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "DIERef.h"
+#include "lldb/Utility/DataEncoder.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "llvm/Support/Format.h"
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::plugin::dwarf;
+
+void llvm::format_provider<DIERef>::format(const DIERef &ref, raw_ostream &OS,
+ StringRef Style) {
+ if (ref.file_index())
+ OS << format_hex_no_prefix(*ref.file_index(), 8) << "/";
+ OS << (ref.section() == DIERef::DebugInfo ? "INFO" : "TYPE");
+ OS << "/" << format_hex_no_prefix(ref.die_offset(), 8);
+}
+
+std::optional<DIERef> DIERef::Decode(const DataExtractor &data,
+ lldb::offset_t *offset_ptr) {
+ DIERef die_ref(data.GetU64(offset_ptr));
+
+ // DIE offsets can't be zero and if we fail to decode something from data,
+ // it will return 0
+ if (!die_ref.die_offset())
+ return std::nullopt;
+
+ return die_ref;
+}
+
+void DIERef::Encode(DataEncoder &encoder) const { encoder.AppendU64(get_id()); }
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DIERef.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DIERef.h
new file mode 100644
index 000000000000..ad443aacb46e
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DIERef.h
@@ -0,0 +1,146 @@
+//===-- DIERef.h ------------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DIEREF_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DIEREF_H
+
+#include "lldb/Core/dwarf.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include <cassert>
+#include <optional>
+
+namespace lldb_private::plugin {
+namespace dwarf {
+/// Identifies a DWARF debug info entry within a given Module. It contains three
+/// "coordinates":
+/// - file_index: identifies the separate stand alone debug info file
+/// that is referred to by the main debug info file. This will be the
+/// index of a DWO file for fission, or the .o file on mac when not
+/// using a dSYM file. If this field is not set, then this references
+/// a DIE inside the original object file.
+/// - section: identifies the section of the debug info entry in the given file:
+/// debug_info or debug_types.
+/// - die_offset: The offset of the debug info entry as an absolute offset from
+/// the beginning of the section specified in the section field.
+class DIERef {
+public:
+ enum Section : uint8_t { DebugInfo, DebugTypes };
+ DIERef(std::optional<uint32_t> file_index, Section section,
+ dw_offset_t die_offset)
+ : m_die_offset(die_offset), m_file_index(file_index.value_or(0)),
+ m_file_index_valid(file_index ? true : false), m_section(section) {
+ assert(this->file_index() == file_index && "File Index is out of range?");
+ }
+
+ explicit DIERef(lldb::user_id_t uid) {
+ m_die_offset = uid & k_die_offset_mask;
+ m_file_index_valid = (uid & k_file_index_valid_bit) != 0;
+ m_file_index = m_file_index_valid
+ ? (uid >> k_die_offset_bit_size) & k_file_index_mask
+ : 0;
+ m_section =
+ (uid & k_section_bit) != 0 ? Section::DebugTypes : Section::DebugInfo;
+ }
+
+ lldb::user_id_t get_id() const {
+ if (m_die_offset == k_die_offset_mask)
+ return LLDB_INVALID_UID;
+
+ return lldb::user_id_t(file_index().value_or(0)) << k_die_offset_bit_size |
+ die_offset() | (m_file_index_valid ? k_file_index_valid_bit : 0) |
+ (section() == Section::DebugTypes ? k_section_bit : 0);
+ }
+
+ std::optional<uint32_t> file_index() const {
+ if (m_file_index_valid)
+ return m_file_index;
+ return std::nullopt;
+ }
+
+ Section section() const { return static_cast<Section>(m_section); }
+
+ dw_offset_t die_offset() const { return m_die_offset; }
+
+ bool operator<(DIERef other) const {
+ if (m_file_index_valid != other.m_file_index_valid)
+ return m_file_index_valid < other.m_file_index_valid;
+ if (m_file_index_valid && (m_file_index != other.m_file_index))
+ return m_file_index < other.m_file_index;
+ if (m_section != other.m_section)
+ return m_section < other.m_section;
+ return m_die_offset < other.m_die_offset;
+ }
+
+ bool operator==(const DIERef &rhs) const {
+ return file_index() == rhs.file_index() && m_section == rhs.m_section &&
+ m_die_offset == rhs.m_die_offset;
+ }
+
+ bool operator!=(const DIERef &rhs) const { return !(*this == rhs); }
+
+ /// Decode a serialized version of this object from data.
+ ///
+ /// \param data
+ /// The decoder object that references the serialized data.
+ ///
+ /// \param offset_ptr
+ /// A pointer that contains the offset from which the data will be decoded
+ /// from that gets updated as data gets decoded.
+ ///
+ /// \return
+ /// Returns a valid DIERef if decoding succeeded, std::nullopt if there was
+ /// unsufficient or invalid values that were decoded.
+ static std::optional<DIERef> Decode(const DataExtractor &data,
+ lldb::offset_t *offset_ptr);
+
+ /// Encode this object into a data encoder object.
+ ///
+ /// This allows this object to be serialized to disk.
+ ///
+ /// \param encoder
+ /// A data encoder object that serialized bytes will be encoded into.
+ ///
+ void Encode(DataEncoder &encoder) const;
+
+ static constexpr uint64_t k_die_offset_bit_size = DW_DIE_OFFSET_MAX_BITSIZE;
+ static constexpr uint64_t k_file_index_bit_size =
+ 64 - DW_DIE_OFFSET_MAX_BITSIZE - /* size of control bits */ 2;
+
+ static constexpr uint64_t k_file_index_valid_bit =
+ (1ull << (k_file_index_bit_size + k_die_offset_bit_size));
+ static constexpr uint64_t k_section_bit =
+ (1ull << (k_file_index_bit_size + k_die_offset_bit_size + 1));
+ static constexpr uint64_t
+ k_file_index_mask = (~0ull) >> (64 - k_file_index_bit_size); // 0x3fffff;
+ static constexpr uint64_t k_die_offset_mask = (~0ull) >>
+ (64 - k_die_offset_bit_size);
+
+private:
+ // Allow 2TB of .debug_info/.debug_types offset
+ dw_offset_t m_die_offset : k_die_offset_bit_size;
+ // Used for DWO index or for .o file index on mac
+ dw_offset_t m_file_index : k_file_index_bit_size;
+ // Set to 1 if m_file_index is a DWO number
+ dw_offset_t m_file_index_valid : 1;
+ // Set to 0 for .debug_info 1 for .debug_types,
+ dw_offset_t m_section : 1;
+};
+static_assert(sizeof(DIERef) == 8);
+
+typedef std::vector<DIERef> DIEArray;
+} // namespace dwarf
+} // namespace lldb_private::plugin
+
+namespace llvm {
+template <> struct format_provider<lldb_private::plugin::dwarf::DIERef> {
+ static void format(const lldb_private::plugin::dwarf::DIERef &ref,
+ raw_ostream &OS, StringRef Style);
+};
+} // namespace llvm
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DIEREF_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.cpp
new file mode 100644
index 000000000000..409e9bb37ab2
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.cpp
@@ -0,0 +1,141 @@
+//===-- DWARFASTParser.cpp ------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFASTParser.h"
+#include "DWARFAttribute.h"
+#include "DWARFDIE.h"
+#include "SymbolFileDWARF.h"
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Target/StackFrame.h"
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::dwarf;
+using namespace lldb_private::plugin::dwarf;
+
+std::optional<SymbolFile::ArrayInfo>
+DWARFASTParser::ParseChildArrayInfo(const DWARFDIE &parent_die,
+ const ExecutionContext *exe_ctx) {
+ SymbolFile::ArrayInfo array_info;
+ if (!parent_die)
+ return std::nullopt;
+
+ for (DWARFDIE die : parent_die.children()) {
+ const dw_tag_t tag = die.Tag();
+ if (tag != DW_TAG_subrange_type)
+ continue;
+
+ DWARFAttributes attributes = die.GetAttributes();
+ if (attributes.Size() == 0)
+ continue;
+
+ uint64_t num_elements = 0;
+ uint64_t lower_bound = 0;
+ uint64_t upper_bound = 0;
+ bool upper_bound_valid = false;
+ for (size_t i = 0; i < attributes.Size(); ++i) {
+ const dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(i, form_value)) {
+ switch (attr) {
+ case DW_AT_name:
+ break;
+
+ case DW_AT_count:
+ if (DWARFDIE var_die = die.GetReferencedDIE(DW_AT_count)) {
+ if (var_die.Tag() == DW_TAG_variable)
+ if (exe_ctx) {
+ if (auto frame = exe_ctx->GetFrameSP()) {
+ Status error;
+ lldb::VariableSP var_sp;
+ auto valobj_sp = frame->GetValueForVariableExpressionPath(
+ var_die.GetName(), eNoDynamicValues, 0, var_sp, error);
+ if (valobj_sp) {
+ num_elements = valobj_sp->GetValueAsUnsigned(0);
+ break;
+ }
+ }
+ }
+ } else
+ num_elements = form_value.Unsigned();
+ break;
+
+ case DW_AT_bit_stride:
+ array_info.bit_stride = form_value.Unsigned();
+ break;
+
+ case DW_AT_byte_stride:
+ array_info.byte_stride = form_value.Unsigned();
+ break;
+
+ case DW_AT_lower_bound:
+ lower_bound = form_value.Unsigned();
+ break;
+
+ case DW_AT_upper_bound:
+ upper_bound_valid = true;
+ upper_bound = form_value.Unsigned();
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ if (num_elements == 0) {
+ if (upper_bound_valid && upper_bound >= lower_bound)
+ num_elements = upper_bound - lower_bound + 1;
+ }
+
+ array_info.element_orders.push_back(num_elements);
+ }
+ return array_info;
+}
+
+Type *DWARFASTParser::GetTypeForDIE(const DWARFDIE &die) {
+ if (!die)
+ return nullptr;
+
+ SymbolFileDWARF *dwarf = die.GetDWARF();
+ if (!dwarf)
+ return nullptr;
+
+ DWARFAttributes attributes = die.GetAttributes();
+ if (attributes.Size() == 0)
+ return nullptr;
+
+ DWARFFormValue type_die_form;
+ for (size_t i = 0; i < attributes.Size(); ++i) {
+ dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+
+ if (attr == DW_AT_type && attributes.ExtractFormValueAtIndex(i, form_value))
+ return dwarf->ResolveTypeUID(form_value.Reference(), true);
+ }
+
+ return nullptr;
+}
+
+AccessType
+DWARFASTParser::GetAccessTypeFromDWARF(uint32_t dwarf_accessibility) {
+ switch (dwarf_accessibility) {
+ case DW_ACCESS_public:
+ return eAccessPublic;
+ case DW_ACCESS_private:
+ return eAccessPrivate;
+ case DW_ACCESS_protected:
+ return eAccessProtected;
+ default:
+ break;
+ }
+ return eAccessNone;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h
new file mode 100644
index 000000000000..abaeb2502cbb
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h
@@ -0,0 +1,79 @@
+//===-- DWARFASTParser.h ----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFASTPARSER_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFASTPARSER_H
+
+#include "DWARFDefines.h"
+#include "lldb/Core/PluginInterface.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Symbol/CompilerDecl.h"
+#include "lldb/Symbol/CompilerDeclContext.h"
+#include "lldb/lldb-enumerations.h"
+#include <optional>
+
+namespace lldb_private {
+class CompileUnit;
+class ExecutionContext;
+}
+
+namespace lldb_private::plugin {
+namespace dwarf {
+class DWARFDIE;
+class SymbolFileDWARF;
+
+class DWARFASTParser {
+public:
+ enum class Kind { DWARFASTParserClang };
+ DWARFASTParser(Kind kind) : m_kind(kind) {}
+
+ virtual ~DWARFASTParser() = default;
+
+ virtual lldb::TypeSP ParseTypeFromDWARF(const SymbolContext &sc,
+ const DWARFDIE &die,
+ bool *type_is_new_ptr) = 0;
+
+ virtual ConstString ConstructDemangledNameFromDWARF(const DWARFDIE &die) = 0;
+
+ virtual Function *ParseFunctionFromDWARF(CompileUnit &comp_unit,
+ const DWARFDIE &die,
+ const AddressRange &range) = 0;
+
+ virtual bool CompleteTypeFromDWARF(const DWARFDIE &die, Type *type,
+ CompilerType &compiler_type) = 0;
+
+ virtual CompilerDecl GetDeclForUIDFromDWARF(const DWARFDIE &die) = 0;
+
+ virtual CompilerDeclContext
+ GetDeclContextForUIDFromDWARF(const DWARFDIE &die) = 0;
+
+ virtual CompilerDeclContext
+ GetDeclContextContainingUIDFromDWARF(const DWARFDIE &die) = 0;
+
+ virtual void EnsureAllDIEsInDeclContextHaveBeenParsed(
+ CompilerDeclContext decl_context) = 0;
+
+ virtual std::string GetDIEClassTemplateParams(const DWARFDIE &die) = 0;
+
+ static std::optional<SymbolFile::ArrayInfo>
+ ParseChildArrayInfo(const DWARFDIE &parent_die,
+ const ExecutionContext *exe_ctx = nullptr);
+
+ lldb_private::Type *GetTypeForDIE(const DWARFDIE &die);
+
+ static lldb::AccessType GetAccessTypeFromDWARF(uint32_t dwarf_accessibility);
+
+ Kind GetKind() const { return m_kind; }
+
+private:
+ const Kind m_kind;
+};
+} // namespace dwarf
+} // namespace lldb_private::plugin
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFASTPARSER_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
new file mode 100644
index 000000000000..ac769ad9fbd5
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -0,0 +1,3862 @@
+//===-- DWARFASTParserClang.cpp -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <cstdlib>
+
+#include "DWARFASTParser.h"
+#include "DWARFASTParserClang.h"
+#include "DWARFDebugInfo.h"
+#include "DWARFDeclContext.h"
+#include "DWARFDefines.h"
+#include "SymbolFileDWARF.h"
+#include "SymbolFileDWARFDebugMap.h"
+#include "SymbolFileDWARFDwo.h"
+#include "UniqueDWARFASTType.h"
+
+#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
+#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h"
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
+#include "Plugins/Language/ObjC/ObjCLanguage.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Symbol/TypeList.h"
+#include "lldb/Symbol/TypeMap.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/Language.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
+
+#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Type.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Demangle/Demangle.h"
+
+#include <map>
+#include <memory>
+#include <optional>
+#include <vector>
+
+//#define ENABLE_DEBUG_PRINTF // COMMENT OUT THIS LINE PRIOR TO CHECKIN
+
+#ifdef ENABLE_DEBUG_PRINTF
+#include <cstdio>
+#define DEBUG_PRINTF(fmt, ...) printf(fmt, __VA_ARGS__)
+#else
+#define DEBUG_PRINTF(fmt, ...)
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::dwarf;
+using namespace lldb_private::plugin::dwarf;
+
+DWARFASTParserClang::DWARFASTParserClang(TypeSystemClang &ast)
+ : DWARFASTParser(Kind::DWARFASTParserClang), m_ast(ast),
+ m_die_to_decl_ctx(), m_decl_ctx_to_die() {}
+
+DWARFASTParserClang::~DWARFASTParserClang() = default;
+
+static bool DeclKindIsCXXClass(clang::Decl::Kind decl_kind) {
+ switch (decl_kind) {
+ case clang::Decl::CXXRecord:
+ case clang::Decl::ClassTemplateSpecialization:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+
+ClangASTImporter &DWARFASTParserClang::GetClangASTImporter() {
+ if (!m_clang_ast_importer_up) {
+ m_clang_ast_importer_up = std::make_unique<ClangASTImporter>();
+ }
+ return *m_clang_ast_importer_up;
+}
+
+/// Detect a forward declaration that is nested in a DW_TAG_module.
+static bool IsClangModuleFwdDecl(const DWARFDIE &Die) {
+ if (!Die.GetAttributeValueAsUnsigned(DW_AT_declaration, 0))
+ return false;
+ auto Parent = Die.GetParent();
+ while (Parent.IsValid()) {
+ if (Parent.Tag() == DW_TAG_module)
+ return true;
+ Parent = Parent.GetParent();
+ }
+ return false;
+}
+
+static DWARFDIE GetContainingClangModuleDIE(const DWARFDIE &die) {
+ if (die.IsValid()) {
+ DWARFDIE top_module_die;
+ // Now make sure this DIE is scoped in a DW_TAG_module tag and return true
+ // if so
+ for (DWARFDIE parent = die.GetParent(); parent.IsValid();
+ parent = parent.GetParent()) {
+ const dw_tag_t tag = parent.Tag();
+ if (tag == DW_TAG_module)
+ top_module_die = parent;
+ else if (tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit)
+ break;
+ }
+
+ return top_module_die;
+ }
+ return DWARFDIE();
+}
+
+static lldb::ModuleSP GetContainingClangModule(const DWARFDIE &die) {
+ if (die.IsValid()) {
+ DWARFDIE clang_module_die = GetContainingClangModuleDIE(die);
+
+ if (clang_module_die) {
+ const char *module_name = clang_module_die.GetName();
+ if (module_name)
+ return die.GetDWARF()->GetExternalModule(
+ lldb_private::ConstString(module_name));
+ }
+ }
+ return lldb::ModuleSP();
+}
+
+// Returns true if the given artificial field name should be ignored when
+// parsing the DWARF.
+static bool ShouldIgnoreArtificialField(llvm::StringRef FieldName) {
+ return FieldName.starts_with("_vptr$")
+ // gdb emit vtable pointer as "_vptr.classname"
+ || FieldName.starts_with("_vptr.");
+}
+
+/// Returns true for C++ constructs represented by clang::CXXRecordDecl
+static bool TagIsRecordType(dw_tag_t tag) {
+ switch (tag) {
+ case DW_TAG_class_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ return true;
+ default:
+ return false;
+ }
+}
+
+TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc,
+ const DWARFDIE &die,
+ Log *log) {
+ ModuleSP clang_module_sp = GetContainingClangModule(die);
+ if (!clang_module_sp)
+ return TypeSP();
+
+ // If this type comes from a Clang module, recursively look in the
+ // DWARF section of the .pcm file in the module cache. Clang
+ // generates DWO skeleton units as breadcrumbs to find them.
+ std::vector<lldb_private::CompilerContext> die_context = die.GetDeclContext();
+ TypeQuery query(die_context, TypeQueryOptions::e_module_search |
+ TypeQueryOptions::e_find_one);
+ TypeResults results;
+
+ // The type in the Clang module must have the same language as the current CU.
+ query.AddLanguage(SymbolFileDWARF::GetLanguageFamily(*die.GetCU()));
+ clang_module_sp->FindTypes(query, results);
+ TypeSP pcm_type_sp = results.GetTypeMap().FirstType();
+ if (!pcm_type_sp) {
+ // Since this type is defined in one of the Clang modules imported
+ // by this symbol file, search all of them. Instead of calling
+ // sym_file->FindTypes(), which would return this again, go straight
+ // to the imported modules.
+ auto &sym_file = die.GetCU()->GetSymbolFileDWARF();
+
+ // Well-formed clang modules never form cycles; guard against corrupted
+ // ones by inserting the current file.
+ results.AlreadySearched(&sym_file);
+ sym_file.ForEachExternalModule(
+ *sc.comp_unit, results.GetSearchedSymbolFiles(), [&](Module &module) {
+ module.FindTypes(query, results);
+ pcm_type_sp = results.GetTypeMap().FirstType();
+ return (bool)pcm_type_sp;
+ });
+ }
+
+ if (!pcm_type_sp)
+ return TypeSP();
+
+ // We found a real definition for this type in the Clang module, so lets use
+ // it and cache the fact that we found a complete type for this die.
+ lldb_private::CompilerType pcm_type = pcm_type_sp->GetForwardCompilerType();
+ lldb_private::CompilerType type =
+ GetClangASTImporter().CopyType(m_ast, pcm_type);
+
+ if (!type)
+ return TypeSP();
+
+ // Under normal operation pcm_type is a shallow forward declaration
+ // that gets completed later. This is necessary to support cyclic
+ // data structures. If, however, pcm_type is already complete (for
+ // example, because it was loaded for a different target before),
+ // the definition needs to be imported right away, too.
+ // Type::ResolveClangType() effectively ignores the ResolveState
+ // inside type_sp and only looks at IsDefined(), so it never calls
+ // ClangASTImporter::ASTImporterDelegate::ImportDefinitionTo(),
+ // which does extra work for Objective-C classes. This would result
+ // in only the forward declaration to be visible.
+ if (pcm_type.IsDefined())
+ GetClangASTImporter().RequireCompleteType(ClangUtil::GetQualType(type));
+
+ SymbolFileDWARF *dwarf = die.GetDWARF();
+ auto type_sp = dwarf->MakeType(
+ die.GetID(), pcm_type_sp->GetName(), pcm_type_sp->GetByteSize(nullptr),
+ nullptr, LLDB_INVALID_UID, Type::eEncodingInvalid,
+ &pcm_type_sp->GetDeclaration(), type, Type::ResolveState::Forward,
+ TypePayloadClang(GetOwningClangModule(die)));
+ clang::TagDecl *tag_decl = TypeSystemClang::GetAsTagDecl(type);
+ if (tag_decl) {
+ LinkDeclContextToDIE(tag_decl, die);
+ } else {
+ clang::DeclContext *defn_decl_ctx = GetCachedClangDeclContextForDIE(die);
+ if (defn_decl_ctx)
+ LinkDeclContextToDIE(defn_decl_ctx, die);
+ }
+
+ return type_sp;
+}
+
+/// This function ensures we are able to add members (nested types, functions,
+/// etc.) to this type. It does so by starting its definition even if one cannot
+/// be found in the debug info. This means the type may need to be "forcibly
+/// completed" later -- see CompleteTypeFromDWARF).
+static void PrepareContextToReceiveMembers(TypeSystemClang &ast,
+ ClangASTImporter &ast_importer,
+ clang::DeclContext *decl_ctx,
+ DWARFDIE die,
+ const char *type_name_cstr) {
+ auto *tag_decl_ctx = clang::dyn_cast<clang::TagDecl>(decl_ctx);
+ if (!tag_decl_ctx)
+ return; // Non-tag context are always ready.
+
+ // We have already completed the type or it is already prepared.
+ if (tag_decl_ctx->isCompleteDefinition() || tag_decl_ctx->isBeingDefined())
+ return;
+
+ // If this tag was imported from another AST context (in the gmodules case),
+ // we can complete the type by doing a full import.
+
+ // If this type was not imported from an external AST, there's nothing to do.
+ CompilerType type = ast.GetTypeForDecl(tag_decl_ctx);
+ if (type && ast_importer.CanImport(type)) {
+ auto qual_type = ClangUtil::GetQualType(type);
+ if (ast_importer.RequireCompleteType(qual_type))
+ return;
+ die.GetDWARF()->GetObjectFile()->GetModule()->ReportError(
+ "Unable to complete the Decl context for DIE {0} at offset "
+ "{1:x16}.\nPlease file a bug report.",
+ type_name_cstr ? type_name_cstr : "", die.GetOffset());
+ }
+
+ // We don't have a type definition and/or the import failed, but we need to
+ // add members to it. Start the definition to make that possible. If the type
+ // has no external storage we also have to complete the definition. Otherwise,
+ // that will happen when we are asked to complete the type
+ // (CompleteTypeFromDWARF).
+ ast.StartTagDeclarationDefinition(type);
+ if (!tag_decl_ctx->hasExternalLexicalStorage()) {
+ ast.SetDeclIsForcefullyCompleted(tag_decl_ctx);
+ ast.CompleteTagDeclarationDefinition(type);
+ }
+}
+
+ParsedDWARFTypeAttributes::ParsedDWARFTypeAttributes(const DWARFDIE &die) {
+ DWARFAttributes attributes = die.GetAttributes();
+ for (size_t i = 0; i < attributes.Size(); ++i) {
+ dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (!attributes.ExtractFormValueAtIndex(i, form_value))
+ continue;
+ switch (attr) {
+ default:
+ break;
+ case DW_AT_abstract_origin:
+ abstract_origin = form_value;
+ break;
+
+ case DW_AT_accessibility:
+ accessibility =
+ DWARFASTParser::GetAccessTypeFromDWARF(form_value.Unsigned());
+ break;
+
+ case DW_AT_artificial:
+ is_artificial = form_value.Boolean();
+ break;
+
+ case DW_AT_bit_stride:
+ bit_stride = form_value.Unsigned();
+ break;
+
+ case DW_AT_byte_size:
+ byte_size = form_value.Unsigned();
+ break;
+
+ case DW_AT_alignment:
+ alignment = form_value.Unsigned();
+ break;
+
+ case DW_AT_byte_stride:
+ byte_stride = form_value.Unsigned();
+ break;
+
+ case DW_AT_calling_convention:
+ calling_convention = form_value.Unsigned();
+ break;
+
+ case DW_AT_containing_type:
+ containing_type = form_value;
+ break;
+
+ case DW_AT_decl_file:
+ // die.GetCU() can differ if DW_AT_specification uses DW_FORM_ref_addr.
+ decl.SetFile(
+ attributes.CompileUnitAtIndex(i)->GetFile(form_value.Unsigned()));
+ break;
+ case DW_AT_decl_line:
+ decl.SetLine(form_value.Unsigned());
+ break;
+ case DW_AT_decl_column:
+ decl.SetColumn(form_value.Unsigned());
+ break;
+
+ case DW_AT_declaration:
+ is_forward_declaration = form_value.Boolean();
+ break;
+
+ case DW_AT_encoding:
+ encoding = form_value.Unsigned();
+ break;
+
+ case DW_AT_enum_class:
+ is_scoped_enum = form_value.Boolean();
+ break;
+
+ case DW_AT_explicit:
+ is_explicit = form_value.Boolean();
+ break;
+
+ case DW_AT_external:
+ if (form_value.Unsigned())
+ storage = clang::SC_Extern;
+ break;
+
+ case DW_AT_inline:
+ is_inline = form_value.Boolean();
+ break;
+
+ case DW_AT_linkage_name:
+ case DW_AT_MIPS_linkage_name:
+ mangled_name = form_value.AsCString();
+ break;
+
+ case DW_AT_name:
+ name.SetCString(form_value.AsCString());
+ break;
+
+ case DW_AT_object_pointer:
+ object_pointer = form_value.Reference();
+ break;
+
+ case DW_AT_signature:
+ signature = form_value;
+ break;
+
+ case DW_AT_specification:
+ specification = form_value;
+ break;
+
+ case DW_AT_type:
+ type = form_value;
+ break;
+
+ case DW_AT_virtuality:
+ is_virtual = form_value.Boolean();
+ break;
+
+ case DW_AT_APPLE_objc_complete_type:
+ is_complete_objc_class = form_value.Signed();
+ break;
+
+ case DW_AT_APPLE_objc_direct:
+ is_objc_direct_call = true;
+ break;
+
+ case DW_AT_APPLE_runtime_class:
+ class_language = (LanguageType)form_value.Signed();
+ break;
+
+ case DW_AT_GNU_vector:
+ is_vector = form_value.Boolean();
+ break;
+ case DW_AT_export_symbols:
+ exports_symbols = form_value.Boolean();
+ break;
+ case DW_AT_rvalue_reference:
+ ref_qual = clang::RQ_RValue;
+ break;
+ case DW_AT_reference:
+ ref_qual = clang::RQ_LValue;
+ break;
+ }
+ }
+}
+
+static std::string GetUnitName(const DWARFDIE &die) {
+ if (DWARFUnit *unit = die.GetCU())
+ return unit->GetAbsolutePath().GetPath();
+ return "<missing DWARF unit path>";
+}
+
+TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc,
+ const DWARFDIE &die,
+ bool *type_is_new_ptr) {
+ if (type_is_new_ptr)
+ *type_is_new_ptr = false;
+
+ if (!die)
+ return nullptr;
+
+ Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups);
+
+ SymbolFileDWARF *dwarf = die.GetDWARF();
+ if (log) {
+ DWARFDIE context_die;
+ clang::DeclContext *context =
+ GetClangDeclContextContainingDIE(die, &context_die);
+
+ dwarf->GetObjectFile()->GetModule()->LogMessage(
+ log,
+ "DWARFASTParserClang::ParseTypeFromDWARF "
+ "(die = {0:x16}, decl_ctx = {1:p} (die "
+ "{2:x16})) {3} ({4}) name = '{5}')",
+ die.GetOffset(), static_cast<void *>(context), context_die.GetOffset(),
+ DW_TAG_value_to_name(die.Tag()), die.Tag(), die.GetName());
+ }
+
+ // Set a bit that lets us know that we are currently parsing this
+ if (auto [it, inserted] =
+ dwarf->GetDIEToType().try_emplace(die.GetDIE(), DIE_IS_BEING_PARSED);
+ !inserted) {
+ if (it->getSecond() == nullptr || it->getSecond() == DIE_IS_BEING_PARSED)
+ return nullptr;
+ return it->getSecond()->shared_from_this();
+ }
+
+ ParsedDWARFTypeAttributes attrs(die);
+
+ TypeSP type_sp;
+ if (DWARFDIE signature_die = attrs.signature.Reference()) {
+ type_sp = ParseTypeFromDWARF(sc, signature_die, type_is_new_ptr);
+ if (type_sp) {
+ if (clang::DeclContext *decl_ctx =
+ GetCachedClangDeclContextForDIE(signature_die))
+ LinkDeclContextToDIE(decl_ctx, die);
+ }
+ } else {
+ if (type_is_new_ptr)
+ *type_is_new_ptr = true;
+
+ const dw_tag_t tag = die.Tag();
+
+ switch (tag) {
+ case DW_TAG_typedef:
+ case DW_TAG_base_type:
+ case DW_TAG_pointer_type:
+ case DW_TAG_reference_type:
+ case DW_TAG_rvalue_reference_type:
+ case DW_TAG_const_type:
+ case DW_TAG_restrict_type:
+ case DW_TAG_volatile_type:
+ case DW_TAG_LLVM_ptrauth_type:
+ case DW_TAG_atomic_type:
+ case DW_TAG_unspecified_type:
+ type_sp = ParseTypeModifier(sc, die, attrs);
+ break;
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_class_type:
+ type_sp = ParseStructureLikeDIE(sc, die, attrs);
+ break;
+ case DW_TAG_enumeration_type:
+ type_sp = ParseEnum(sc, die, attrs);
+ break;
+ case DW_TAG_inlined_subroutine:
+ case DW_TAG_subprogram:
+ case DW_TAG_subroutine_type:
+ type_sp = ParseSubroutine(die, attrs);
+ break;
+ case DW_TAG_array_type:
+ type_sp = ParseArrayType(die, attrs);
+ break;
+ case DW_TAG_ptr_to_member_type:
+ type_sp = ParsePointerToMemberType(die, attrs);
+ break;
+ default:
+ dwarf->GetObjectFile()->GetModule()->ReportError(
+ "[{0:x16}]: unhandled type tag {1:x4} ({2}), "
+ "please file a bug and "
+ "attach the file at the start of this error message",
+ die.GetOffset(), tag, DW_TAG_value_to_name(tag));
+ break;
+ }
+ UpdateSymbolContextScopeForType(sc, die, type_sp);
+ }
+ if (type_sp) {
+ dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get();
+ }
+ return type_sp;
+}
+
+static std::optional<uint32_t>
+ExtractDataMemberLocation(DWARFDIE const &die, DWARFFormValue const &form_value,
+ ModuleSP module_sp) {
+ Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups);
+
+ // With DWARF 3 and later, if the value is an integer constant,
+ // this form value is the offset in bytes from the beginning of
+ // the containing entity.
+ if (!form_value.BlockData())
+ return form_value.Unsigned();
+
+ Value initialValue(0);
+ const DWARFDataExtractor &debug_info_data = die.GetData();
+ uint32_t block_length = form_value.Unsigned();
+ uint32_t block_offset =
+ form_value.BlockData() - debug_info_data.GetDataStart();
+
+ llvm::Expected<Value> memberOffset = DWARFExpression::Evaluate(
+ /*ExecutionContext=*/nullptr,
+ /*RegisterContext=*/nullptr, module_sp,
+ DataExtractor(debug_info_data, block_offset, block_length), die.GetCU(),
+ eRegisterKindDWARF, &initialValue, nullptr);
+ if (!memberOffset) {
+ LLDB_LOG_ERROR(log, memberOffset.takeError(),
+ "ExtractDataMemberLocation failed: {0}");
+ return {};
+ }
+
+ return memberOffset->ResolveValue(nullptr).UInt();
+}
+
+static TypePayloadClang GetPtrAuthMofidierPayload(const DWARFDIE &die) {
+ auto getAttr = [&](llvm::dwarf::Attribute Attr, unsigned defaultValue = 0) {
+ return die.GetAttributeValueAsUnsigned(Attr, defaultValue);
+ };
+ const unsigned key = getAttr(DW_AT_LLVM_ptrauth_key);
+ const bool addr_disc = getAttr(DW_AT_LLVM_ptrauth_address_discriminated);
+ const unsigned extra = getAttr(DW_AT_LLVM_ptrauth_extra_discriminator);
+ const bool isapointer = getAttr(DW_AT_LLVM_ptrauth_isa_pointer);
+ const bool authenticates_null_values =
+ getAttr(DW_AT_LLVM_ptrauth_authenticates_null_values);
+ const unsigned authentication_mode_int = getAttr(
+ DW_AT_LLVM_ptrauth_authentication_mode,
+ static_cast<unsigned>(clang::PointerAuthenticationMode::SignAndAuth));
+ clang::PointerAuthenticationMode authentication_mode =
+ clang::PointerAuthenticationMode::SignAndAuth;
+ if (authentication_mode_int >=
+ static_cast<unsigned>(clang::PointerAuthenticationMode::None) &&
+ authentication_mode_int <=
+ static_cast<unsigned>(
+ clang::PointerAuthenticationMode::SignAndAuth)) {
+ authentication_mode =
+ static_cast<clang::PointerAuthenticationMode>(authentication_mode_int);
+ } else {
+ die.GetDWARF()->GetObjectFile()->GetModule()->ReportError(
+ "[{0:x16}]: invalid pointer authentication mode method {1:x4}",
+ die.GetOffset(), authentication_mode_int);
+ }
+ auto ptr_auth = clang::PointerAuthQualifier::Create(
+ key, addr_disc, extra, authentication_mode, isapointer,
+ authenticates_null_values);
+ return TypePayloadClang(ptr_auth.getAsOpaqueValue());
+}
+
+lldb::TypeSP
+DWARFASTParserClang::ParseTypeModifier(const SymbolContext &sc,
+ const DWARFDIE &die,
+ ParsedDWARFTypeAttributes &attrs) {
+ Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups);
+ SymbolFileDWARF *dwarf = die.GetDWARF();
+ const dw_tag_t tag = die.Tag();
+ LanguageType cu_language = SymbolFileDWARF::GetLanguage(*die.GetCU());
+ Type::ResolveState resolve_state = Type::ResolveState::Unresolved;
+ Type::EncodingDataType encoding_data_type = Type::eEncodingIsUID;
+ TypePayloadClang payload(GetOwningClangModule(die));
+ TypeSP type_sp;
+ CompilerType clang_type;
+
+ if (tag == DW_TAG_typedef) {
+ // DeclContext will be populated when the clang type is materialized in
+ // Type::ResolveCompilerType.
+ PrepareContextToReceiveMembers(
+ m_ast, GetClangASTImporter(),
+ GetClangDeclContextContainingDIE(die, nullptr), die,
+ attrs.name.GetCString());
+
+ if (attrs.type.IsValid()) {
+ // Try to parse a typedef from the (DWARF embedded in the) Clang
+ // module file first as modules can contain typedef'ed
+ // structures that have no names like:
+ //
+ // typedef struct { int a; } Foo;
+ //
+ // In this case we will have a structure with no name and a
+ // typedef named "Foo" that points to this unnamed
+ // structure. The name in the typedef is the only identifier for
+ // the struct, so always try to get typedefs from Clang modules
+ // if possible.
+ //
+ // The type_sp returned will be empty if the typedef doesn't
+ // exist in a module file, so it is cheap to call this function
+ // just to check.
+ //
+ // If we don't do this we end up creating a TypeSP that says
+ // this is a typedef to type 0x123 (the DW_AT_type value would
+ // be 0x123 in the DW_TAG_typedef), and this is the unnamed
+ // structure type. We will have a hard time tracking down an
+ // unnammed structure type in the module debug info, so we make
+ // sure we don't get into this situation by always resolving
+ // typedefs from the module.
+ const DWARFDIE encoding_die = attrs.type.Reference();
+
+ // First make sure that the die that this is typedef'ed to _is_
+ // just a declaration (DW_AT_declaration == 1), not a full
+ // definition since template types can't be represented in
+ // modules since only concrete instances of templates are ever
+ // emitted and modules won't contain those
+ if (encoding_die &&
+ encoding_die.GetAttributeValueAsUnsigned(DW_AT_declaration, 0) == 1) {
+ type_sp = ParseTypeFromClangModule(sc, die, log);
+ if (type_sp)
+ return type_sp;
+ }
+ }
+ }
+
+ DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\") type => 0x%8.8lx\n", die.GetID(),
+ DW_TAG_value_to_name(tag), type_name_cstr,
+ encoding_uid.Reference());
+
+ switch (tag) {
+ default:
+ break;
+
+ case DW_TAG_unspecified_type:
+ if (attrs.name == "nullptr_t" || attrs.name == "decltype(nullptr)") {
+ resolve_state = Type::ResolveState::Full;
+ clang_type = m_ast.GetBasicType(eBasicTypeNullPtr);
+ break;
+ }
+ // Fall through to base type below in case we can handle the type
+ // there...
+ [[fallthrough]];
+
+ case DW_TAG_base_type:
+ resolve_state = Type::ResolveState::Full;
+ clang_type = m_ast.GetBuiltinTypeForDWARFEncodingAndBitSize(
+ attrs.name.GetStringRef(), attrs.encoding,
+ attrs.byte_size.value_or(0) * 8);
+ break;
+
+ case DW_TAG_pointer_type:
+ encoding_data_type = Type::eEncodingIsPointerUID;
+ break;
+ case DW_TAG_reference_type:
+ encoding_data_type = Type::eEncodingIsLValueReferenceUID;
+ break;
+ case DW_TAG_rvalue_reference_type:
+ encoding_data_type = Type::eEncodingIsRValueReferenceUID;
+ break;
+ case DW_TAG_typedef:
+ encoding_data_type = Type::eEncodingIsTypedefUID;
+ break;
+ case DW_TAG_const_type:
+ encoding_data_type = Type::eEncodingIsConstUID;
+ break;
+ case DW_TAG_restrict_type:
+ encoding_data_type = Type::eEncodingIsRestrictUID;
+ break;
+ case DW_TAG_volatile_type:
+ encoding_data_type = Type::eEncodingIsVolatileUID;
+ break;
+ case DW_TAG_LLVM_ptrauth_type:
+ encoding_data_type = Type::eEncodingIsLLVMPtrAuthUID;
+ payload = GetPtrAuthMofidierPayload(die);
+ break;
+ case DW_TAG_atomic_type:
+ encoding_data_type = Type::eEncodingIsAtomicUID;
+ break;
+ }
+
+ if (!clang_type && (encoding_data_type == Type::eEncodingIsPointerUID ||
+ encoding_data_type == Type::eEncodingIsTypedefUID)) {
+ if (tag == DW_TAG_pointer_type) {
+ DWARFDIE target_die = die.GetReferencedDIE(DW_AT_type);
+
+ if (target_die.GetAttributeValueAsUnsigned(DW_AT_APPLE_block, 0)) {
+ // Blocks have a __FuncPtr inside them which is a pointer to a
+ // function of the proper type.
+
+ for (DWARFDIE child_die : target_die.children()) {
+ if (!strcmp(child_die.GetAttributeValueAsString(DW_AT_name, ""),
+ "__FuncPtr")) {
+ DWARFDIE function_pointer_type =
+ child_die.GetReferencedDIE(DW_AT_type);
+
+ if (function_pointer_type) {
+ DWARFDIE function_type =
+ function_pointer_type.GetReferencedDIE(DW_AT_type);
+
+ bool function_type_is_new_pointer;
+ TypeSP lldb_function_type_sp = ParseTypeFromDWARF(
+ sc, function_type, &function_type_is_new_pointer);
+
+ if (lldb_function_type_sp) {
+ clang_type = m_ast.CreateBlockPointerType(
+ lldb_function_type_sp->GetForwardCompilerType());
+ encoding_data_type = Type::eEncodingIsUID;
+ attrs.type.Clear();
+ resolve_state = Type::ResolveState::Full;
+ }
+ }
+
+ break;
+ }
+ }
+ }
+ }
+
+ if (cu_language == eLanguageTypeObjC ||
+ cu_language == eLanguageTypeObjC_plus_plus) {
+ if (attrs.name) {
+ if (attrs.name == "id") {
+ if (log)
+ dwarf->GetObjectFile()->GetModule()->LogMessage(
+ log,
+ "SymbolFileDWARF::ParseType (die = {0:x16}) {1} ({2}) '{3}' "
+ "is Objective-C 'id' built-in type.",
+ die.GetOffset(), DW_TAG_value_to_name(die.Tag()), die.Tag(),
+ die.GetName());
+ clang_type = m_ast.GetBasicType(eBasicTypeObjCID);
+ encoding_data_type = Type::eEncodingIsUID;
+ attrs.type.Clear();
+ resolve_state = Type::ResolveState::Full;
+ } else if (attrs.name == "Class") {
+ if (log)
+ dwarf->GetObjectFile()->GetModule()->LogMessage(
+ log,
+ "SymbolFileDWARF::ParseType (die = {0:x16}) {1} ({2}) '{3}' "
+ "is Objective-C 'Class' built-in type.",
+ die.GetOffset(), DW_TAG_value_to_name(die.Tag()), die.Tag(),
+ die.GetName());
+ clang_type = m_ast.GetBasicType(eBasicTypeObjCClass);
+ encoding_data_type = Type::eEncodingIsUID;
+ attrs.type.Clear();
+ resolve_state = Type::ResolveState::Full;
+ } else if (attrs.name == "SEL") {
+ if (log)
+ dwarf->GetObjectFile()->GetModule()->LogMessage(
+ log,
+ "SymbolFileDWARF::ParseType (die = {0:x16}) {1} ({2}) '{3}' "
+ "is Objective-C 'selector' built-in type.",
+ die.GetOffset(), DW_TAG_value_to_name(die.Tag()), die.Tag(),
+ die.GetName());
+ clang_type = m_ast.GetBasicType(eBasicTypeObjCSel);
+ encoding_data_type = Type::eEncodingIsUID;
+ attrs.type.Clear();
+ resolve_state = Type::ResolveState::Full;
+ }
+ } else if (encoding_data_type == Type::eEncodingIsPointerUID &&
+ attrs.type.IsValid()) {
+ // Clang sometimes erroneously emits id as objc_object*. In that
+ // case we fix up the type to "id".
+
+ const DWARFDIE encoding_die = attrs.type.Reference();
+
+ if (encoding_die && encoding_die.Tag() == DW_TAG_structure_type) {
+ llvm::StringRef struct_name = encoding_die.GetName();
+ if (struct_name == "objc_object") {
+ if (log)
+ dwarf->GetObjectFile()->GetModule()->LogMessage(
+ log,
+ "SymbolFileDWARF::ParseType (die = {0:x16}) {1} ({2}) '{3}' "
+ "is 'objc_object*', which we overrode to 'id'.",
+ die.GetOffset(), DW_TAG_value_to_name(die.Tag()), die.Tag(),
+ die.GetName());
+ clang_type = m_ast.GetBasicType(eBasicTypeObjCID);
+ encoding_data_type = Type::eEncodingIsUID;
+ attrs.type.Clear();
+ resolve_state = Type::ResolveState::Full;
+ }
+ }
+ }
+ }
+ }
+
+ return dwarf->MakeType(die.GetID(), attrs.name, attrs.byte_size, nullptr,
+ attrs.type.Reference().GetID(), encoding_data_type,
+ &attrs.decl, clang_type, resolve_state, payload);
+}
+
+std::string
+DWARFASTParserClang::GetDIEClassTemplateParams(const DWARFDIE &die) {
+ if (llvm::StringRef(die.GetName()).contains("<"))
+ return {};
+
+ TypeSystemClang::TemplateParameterInfos template_param_infos;
+ if (ParseTemplateParameterInfos(die, template_param_infos))
+ return m_ast.PrintTemplateParams(template_param_infos);
+
+ return {};
+}
+
+void DWARFASTParserClang::MapDeclDIEToDefDIE(
+ const lldb_private::plugin::dwarf::DWARFDIE &decl_die,
+ const lldb_private::plugin::dwarf::DWARFDIE &def_die) {
+ LinkDeclContextToDIE(GetCachedClangDeclContextForDIE(decl_die), def_die);
+ SymbolFileDWARF *dwarf = def_die.GetDWARF();
+ ParsedDWARFTypeAttributes decl_attrs(decl_die);
+ ParsedDWARFTypeAttributes def_attrs(def_die);
+ ConstString unique_typename(decl_attrs.name);
+ Declaration decl_declaration(decl_attrs.decl);
+ GetUniqueTypeNameAndDeclaration(
+ decl_die, SymbolFileDWARF::GetLanguage(*decl_die.GetCU()),
+ unique_typename, decl_declaration);
+ if (UniqueDWARFASTType *unique_ast_entry_type =
+ dwarf->GetUniqueDWARFASTTypeMap().Find(
+ unique_typename, decl_die, decl_declaration,
+ decl_attrs.byte_size.value_or(0),
+ decl_attrs.is_forward_declaration)) {
+ unique_ast_entry_type->UpdateToDefDIE(def_die, def_attrs.decl,
+ def_attrs.byte_size.value_or(0));
+ } else if (Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups)) {
+ const dw_tag_t tag = decl_die.Tag();
+ LLDB_LOG(log,
+ "Failed to find {0:x16} {1} ({2}) type \"{3}\" in "
+ "UniqueDWARFASTTypeMap",
+ decl_die.GetID(), DW_TAG_value_to_name(tag), tag, unique_typename);
+ }
+}
+
+TypeSP DWARFASTParserClang::ParseEnum(const SymbolContext &sc,
+ const DWARFDIE &decl_die,
+ ParsedDWARFTypeAttributes &attrs) {
+ Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups);
+ SymbolFileDWARF *dwarf = decl_die.GetDWARF();
+ const dw_tag_t tag = decl_die.Tag();
+
+ DWARFDIE def_die;
+ if (attrs.is_forward_declaration) {
+ if (TypeSP type_sp = ParseTypeFromClangModule(sc, decl_die, log))
+ return type_sp;
+
+ def_die = dwarf->FindDefinitionDIE(decl_die);
+
+ if (!def_die) {
+ SymbolFileDWARFDebugMap *debug_map_symfile = dwarf->GetDebugMapSymfile();
+ if (debug_map_symfile) {
+ // We weren't able to find a full declaration in this DWARF,
+ // see if we have a declaration anywhere else...
+ def_die = debug_map_symfile->FindDefinitionDIE(decl_die);
+ }
+ }
+
+ if (log) {
+ dwarf->GetObjectFile()->GetModule()->LogMessage(
+ log,
+ "SymbolFileDWARF({0:p}) - {1:x16}}: {2} ({3}) type \"{4}\" is a "
+ "forward declaration, complete DIE is {5}",
+ static_cast<void *>(this), decl_die.GetID(), DW_TAG_value_to_name(tag),
+ tag, attrs.name.GetCString(),
+ def_die ? llvm::utohexstr(def_die.GetID()) : "not found");
+ }
+ }
+ if (def_die) {
+ if (auto [it, inserted] = dwarf->GetDIEToType().try_emplace(
+ def_die.GetDIE(), DIE_IS_BEING_PARSED);
+ !inserted) {
+ if (it->getSecond() == nullptr || it->getSecond() == DIE_IS_BEING_PARSED)
+ return nullptr;
+ return it->getSecond()->shared_from_this();
+ }
+ attrs = ParsedDWARFTypeAttributes(def_die);
+ } else {
+ // No definition found. Proceed with the declaration die. We can use it to
+ // create a forward-declared type.
+ def_die = decl_die;
+ }
+
+ CompilerType enumerator_clang_type;
+ if (attrs.type.IsValid()) {
+ Type *enumerator_type =
+ dwarf->ResolveTypeUID(attrs.type.Reference(), true);
+ if (enumerator_type)
+ enumerator_clang_type = enumerator_type->GetFullCompilerType();
+ }
+
+ if (!enumerator_clang_type) {
+ if (attrs.byte_size) {
+ enumerator_clang_type = m_ast.GetBuiltinTypeForDWARFEncodingAndBitSize(
+ "", DW_ATE_signed, *attrs.byte_size * 8);
+ } else {
+ enumerator_clang_type = m_ast.GetBasicType(eBasicTypeInt);
+ }
+ }
+
+ CompilerType clang_type = m_ast.CreateEnumerationType(
+ attrs.name.GetStringRef(), GetClangDeclContextContainingDIE(def_die, nullptr),
+ GetOwningClangModule(def_die), attrs.decl, enumerator_clang_type,
+ attrs.is_scoped_enum);
+ TypeSP type_sp =
+ dwarf->MakeType(def_die.GetID(), attrs.name, attrs.byte_size, nullptr,
+ attrs.type.Reference().GetID(), Type::eEncodingIsUID,
+ &attrs.decl, clang_type, Type::ResolveState::Forward,
+ TypePayloadClang(GetOwningClangModule(def_die)));
+
+ clang::DeclContext *type_decl_ctx =
+ TypeSystemClang::GetDeclContextForType(clang_type);
+ LinkDeclContextToDIE(type_decl_ctx, decl_die);
+ if (decl_die != def_die) {
+ LinkDeclContextToDIE(type_decl_ctx, def_die);
+ dwarf->GetDIEToType()[def_die.GetDIE()] = type_sp.get();
+ // Declaration DIE is inserted into the type map in ParseTypeFromDWARF
+ }
+
+
+ if (TypeSystemClang::StartTagDeclarationDefinition(clang_type)) {
+ if (def_die.HasChildren()) {
+ bool is_signed = false;
+ enumerator_clang_type.IsIntegerType(is_signed);
+ ParseChildEnumerators(clang_type, is_signed,
+ type_sp->GetByteSize(nullptr).value_or(0), def_die);
+ }
+ TypeSystemClang::CompleteTagDeclarationDefinition(clang_type);
+ } else {
+ dwarf->GetObjectFile()->GetModule()->ReportError(
+ "DWARF DIE at {0:x16} named \"{1}\" was not able to start its "
+ "definition.\nPlease file a bug and attach the file at the "
+ "start of this error message",
+ def_die.GetOffset(), attrs.name.GetCString());
+ }
+ return type_sp;
+}
+
+static clang::CallingConv
+ConvertDWARFCallingConventionToClang(const ParsedDWARFTypeAttributes &attrs) {
+ switch (attrs.calling_convention) {
+ case llvm::dwarf::DW_CC_normal:
+ return clang::CC_C;
+ case llvm::dwarf::DW_CC_BORLAND_stdcall:
+ return clang::CC_X86StdCall;
+ case llvm::dwarf::DW_CC_BORLAND_msfastcall:
+ return clang::CC_X86FastCall;
+ case llvm::dwarf::DW_CC_LLVM_vectorcall:
+ return clang::CC_X86VectorCall;
+ case llvm::dwarf::DW_CC_BORLAND_pascal:
+ return clang::CC_X86Pascal;
+ case llvm::dwarf::DW_CC_LLVM_Win64:
+ return clang::CC_Win64;
+ case llvm::dwarf::DW_CC_LLVM_X86_64SysV:
+ return clang::CC_X86_64SysV;
+ case llvm::dwarf::DW_CC_LLVM_X86RegCall:
+ return clang::CC_X86RegCall;
+ default:
+ break;
+ }
+
+ Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups);
+ LLDB_LOG(log, "Unsupported DW_AT_calling_convention value: {0}",
+ attrs.calling_convention);
+ // Use the default calling convention as a fallback.
+ return clang::CC_C;
+}
+
+bool DWARFASTParserClang::ParseObjCMethod(
+ const ObjCLanguage::MethodName &objc_method, const DWARFDIE &die,
+ CompilerType clang_type, const ParsedDWARFTypeAttributes &attrs,
+ bool is_variadic) {
+ SymbolFileDWARF *dwarf = die.GetDWARF();
+ assert(dwarf);
+
+ const auto tag = die.Tag();
+ ConstString class_name(objc_method.GetClassName());
+ if (!class_name)
+ return false;
+
+ TypeSP complete_objc_class_type_sp =
+ dwarf->FindCompleteObjCDefinitionTypeForDIE(DWARFDIE(), class_name,
+ false);
+
+ if (!complete_objc_class_type_sp)
+ return false;
+
+ CompilerType type_clang_forward_type =
+ complete_objc_class_type_sp->GetForwardCompilerType();
+
+ if (!type_clang_forward_type)
+ return false;
+
+ if (!TypeSystemClang::IsObjCObjectOrInterfaceType(type_clang_forward_type))
+ return false;
+
+ clang::ObjCMethodDecl *objc_method_decl = m_ast.AddMethodToObjCObjectType(
+ type_clang_forward_type, attrs.name.GetCString(), clang_type,
+ attrs.is_artificial, is_variadic, attrs.is_objc_direct_call);
+
+ if (!objc_method_decl) {
+ dwarf->GetObjectFile()->GetModule()->ReportError(
+ "[{0:x16}]: invalid Objective-C method {1:x4} ({2}), "
+ "please file a bug and attach the file at the start of "
+ "this error message",
+ die.GetOffset(), tag, DW_TAG_value_to_name(tag));
+ return false;
+ }
+
+ LinkDeclContextToDIE(objc_method_decl, die);
+ m_ast.SetMetadataAsUserID(objc_method_decl, die.GetID());
+
+ return true;
+}
+
+std::pair<bool, TypeSP> DWARFASTParserClang::ParseCXXMethod(
+ const DWARFDIE &die, CompilerType clang_type,
+ const ParsedDWARFTypeAttributes &attrs, const DWARFDIE &decl_ctx_die,
+ bool is_static, bool &ignore_containing_context) {
+ Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups);
+ SymbolFileDWARF *dwarf = die.GetDWARF();
+ assert(dwarf);
+
+ Type *class_type = dwarf->ResolveType(decl_ctx_die);
+ if (!class_type)
+ return {};
+
+ if (class_type->GetID() != decl_ctx_die.GetID() ||
+ IsClangModuleFwdDecl(decl_ctx_die)) {
+
+ // We uniqued the parent class of this function to another
+ // class so we now need to associate all dies under
+ // "decl_ctx_die" to DIEs in the DIE for "class_type"...
+ if (DWARFDIE class_type_die = dwarf->GetDIE(class_type->GetID())) {
+ std::vector<DWARFDIE> failures;
+
+ CopyUniqueClassMethodTypes(decl_ctx_die, class_type_die, class_type,
+ failures);
+
+ // FIXME do something with these failures that's
+ // smarter than just dropping them on the ground.
+ // Unfortunately classes don't like having stuff added
+ // to them after their definitions are complete...
+
+ Type *type_ptr = dwarf->GetDIEToType().lookup(die.GetDIE());
+ if (type_ptr && type_ptr != DIE_IS_BEING_PARSED)
+ return {true, type_ptr->shared_from_this()};
+ }
+ }
+
+ if (attrs.specification.IsValid()) {
+ // We have a specification which we are going to base our
+ // function prototype off of, so we need this type to be
+ // completed so that the m_die_to_decl_ctx for the method in
+ // the specification has a valid clang decl context.
+ class_type->GetForwardCompilerType();
+ // If we have a specification, then the function type should
+ // have been made with the specification and not with this
+ // die.
+ DWARFDIE spec_die = attrs.specification.Reference();
+ clang::DeclContext *spec_clang_decl_ctx =
+ GetClangDeclContextForDIE(spec_die);
+ if (spec_clang_decl_ctx)
+ LinkDeclContextToDIE(spec_clang_decl_ctx, die);
+ else
+ dwarf->GetObjectFile()->GetModule()->ReportWarning(
+ "{0:x8}: DW_AT_specification({1:x16}"
+ ") has no decl\n",
+ die.GetID(), spec_die.GetOffset());
+
+ return {true, nullptr};
+ }
+
+ if (attrs.abstract_origin.IsValid()) {
+ // We have a specification which we are going to base our
+ // function prototype off of, so we need this type to be
+ // completed so that the m_die_to_decl_ctx for the method in
+ // the abstract origin has a valid clang decl context.
+ class_type->GetForwardCompilerType();
+
+ DWARFDIE abs_die = attrs.abstract_origin.Reference();
+ clang::DeclContext *abs_clang_decl_ctx = GetClangDeclContextForDIE(abs_die);
+ if (abs_clang_decl_ctx)
+ LinkDeclContextToDIE(abs_clang_decl_ctx, die);
+ else
+ dwarf->GetObjectFile()->GetModule()->ReportWarning(
+ "{0:x8}: DW_AT_abstract_origin({1:x16}"
+ ") has no decl\n",
+ die.GetID(), abs_die.GetOffset());
+
+ return {true, nullptr};
+ }
+
+ CompilerType class_opaque_type = class_type->GetForwardCompilerType();
+ if (!TypeSystemClang::IsCXXClassType(class_opaque_type))
+ return {};
+
+ PrepareContextToReceiveMembers(
+ m_ast, GetClangASTImporter(),
+ TypeSystemClang::GetDeclContextForType(class_opaque_type), die,
+ attrs.name.GetCString());
+
+ // We have a C++ member function with no children (this pointer!) and clang
+ // will get mad if we try and make a function that isn't well formed in the
+ // DWARF, so we will just skip it...
+ if (!is_static && !die.HasChildren())
+ return {true, nullptr};
+
+ const bool is_attr_used = false;
+ // Neither GCC 4.2 nor clang++ currently set a valid
+ // accessibility in the DWARF for C++ methods...
+ // Default to public for now...
+ const auto accessibility =
+ attrs.accessibility == eAccessNone ? eAccessPublic : attrs.accessibility;
+
+ clang::CXXMethodDecl *cxx_method_decl = m_ast.AddMethodToCXXRecordType(
+ class_opaque_type.GetOpaqueQualType(), attrs.name.GetCString(),
+ attrs.mangled_name, clang_type, accessibility, attrs.is_virtual,
+ is_static, attrs.is_inline, attrs.is_explicit, is_attr_used,
+ attrs.is_artificial);
+
+ if (cxx_method_decl) {
+ LinkDeclContextToDIE(cxx_method_decl, die);
+
+ ClangASTMetadata metadata;
+ metadata.SetUserID(die.GetID());
+
+ char const *object_pointer_name =
+ attrs.object_pointer ? attrs.object_pointer.GetName() : nullptr;
+ if (object_pointer_name) {
+ metadata.SetObjectPtrName(object_pointer_name);
+ LLDB_LOGF(log, "Setting object pointer name: %s on method object %p.\n",
+ object_pointer_name, static_cast<void *>(cxx_method_decl));
+ }
+ m_ast.SetMetadata(cxx_method_decl, metadata);
+ } else {
+ ignore_containing_context = true;
+ }
+
+ // Artificial methods are always handled even when we
+ // don't create a new declaration for them.
+ const bool type_handled = cxx_method_decl != nullptr || attrs.is_artificial;
+
+ return {type_handled, nullptr};
+}
+
+TypeSP
+DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
+ const ParsedDWARFTypeAttributes &attrs) {
+ Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups);
+
+ SymbolFileDWARF *dwarf = die.GetDWARF();
+ const dw_tag_t tag = die.Tag();
+
+ bool is_variadic = false;
+ bool is_static = false;
+ bool has_template_params = false;
+
+ unsigned type_quals = 0;
+
+ DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(),
+ DW_TAG_value_to_name(tag), type_name_cstr);
+
+ CompilerType return_clang_type;
+ Type *func_type = nullptr;
+
+ if (attrs.type.IsValid())
+ func_type = dwarf->ResolveTypeUID(attrs.type.Reference(), true);
+
+ if (func_type)
+ return_clang_type = func_type->GetForwardCompilerType();
+ else
+ return_clang_type = m_ast.GetBasicType(eBasicTypeVoid);
+
+ std::vector<CompilerType> function_param_types;
+ std::vector<clang::ParmVarDecl *> function_param_decls;
+
+ // Parse the function children for the parameters
+
+ DWARFDIE decl_ctx_die;
+ clang::DeclContext *containing_decl_ctx =
+ GetClangDeclContextContainingDIE(die, &decl_ctx_die);
+ const clang::Decl::Kind containing_decl_kind =
+ containing_decl_ctx->getDeclKind();
+
+ bool is_cxx_method = DeclKindIsCXXClass(containing_decl_kind);
+ // Start off static. This will be set to false in
+ // ParseChildParameters(...) if we find a "this" parameters as the
+ // first parameter
+ if (is_cxx_method) {
+ is_static = true;
+ }
+
+ if (die.HasChildren()) {
+ bool skip_artificial = true;
+ ParseChildParameters(containing_decl_ctx, die, skip_artificial, is_static,
+ is_variadic, has_template_params,
+ function_param_types, function_param_decls,
+ type_quals);
+ }
+
+ bool ignore_containing_context = false;
+ // Check for templatized class member functions. If we had any
+ // DW_TAG_template_type_parameter or DW_TAG_template_value_parameter
+ // the DW_TAG_subprogram DIE, then we can't let this become a method in
+ // a class. Why? Because templatized functions are only emitted if one
+ // of the templatized methods is used in the current compile unit and
+ // we will end up with classes that may or may not include these member
+ // functions and this means one class won't match another class
+ // definition and it affects our ability to use a class in the clang
+ // expression parser. So for the greater good, we currently must not
+ // allow any template member functions in a class definition.
+ if (is_cxx_method && has_template_params) {
+ ignore_containing_context = true;
+ is_cxx_method = false;
+ }
+
+ clang::CallingConv calling_convention =
+ ConvertDWARFCallingConventionToClang(attrs);
+
+ // clang_type will get the function prototype clang type after this
+ // call
+ CompilerType clang_type =
+ m_ast.CreateFunctionType(return_clang_type, function_param_types.data(),
+ function_param_types.size(), is_variadic,
+ type_quals, calling_convention, attrs.ref_qual);
+
+ if (attrs.name) {
+ bool type_handled = false;
+ if (tag == DW_TAG_subprogram || tag == DW_TAG_inlined_subroutine) {
+ if (std::optional<const ObjCLanguage::MethodName> objc_method =
+ ObjCLanguage::MethodName::Create(attrs.name.GetStringRef(),
+ true)) {
+ type_handled =
+ ParseObjCMethod(*objc_method, die, clang_type, attrs, is_variadic);
+ } else if (is_cxx_method) {
+ auto [handled, type_sp] =
+ ParseCXXMethod(die, clang_type, attrs, decl_ctx_die, is_static,
+ ignore_containing_context);
+ if (type_sp)
+ return type_sp;
+
+ type_handled = handled;
+ }
+ }
+
+ if (!type_handled) {
+ clang::FunctionDecl *function_decl = nullptr;
+ clang::FunctionDecl *template_function_decl = nullptr;
+
+ if (attrs.abstract_origin.IsValid()) {
+ DWARFDIE abs_die = attrs.abstract_origin.Reference();
+
+ if (dwarf->ResolveType(abs_die)) {
+ function_decl = llvm::dyn_cast_or_null<clang::FunctionDecl>(
+ GetCachedClangDeclContextForDIE(abs_die));
+
+ if (function_decl) {
+ LinkDeclContextToDIE(function_decl, die);
+ }
+ }
+ }
+
+ if (!function_decl) {
+ char *name_buf = nullptr;
+ llvm::StringRef name = attrs.name.GetStringRef();
+
+ // We currently generate function templates with template parameters in
+ // their name. In order to get closer to the AST that clang generates
+ // we want to strip these from the name when creating the AST.
+ if (attrs.mangled_name) {
+ llvm::ItaniumPartialDemangler D;
+ if (!D.partialDemangle(attrs.mangled_name)) {
+ name_buf = D.getFunctionBaseName(nullptr, nullptr);
+ name = name_buf;
+ }
+ }
+
+ // We just have a function that isn't part of a class
+ function_decl = m_ast.CreateFunctionDeclaration(
+ ignore_containing_context ? m_ast.GetTranslationUnitDecl()
+ : containing_decl_ctx,
+ GetOwningClangModule(die), name, clang_type, attrs.storage,
+ attrs.is_inline);
+ std::free(name_buf);
+
+ if (has_template_params) {
+ TypeSystemClang::TemplateParameterInfos template_param_infos;
+ ParseTemplateParameterInfos(die, template_param_infos);
+ template_function_decl = m_ast.CreateFunctionDeclaration(
+ ignore_containing_context ? m_ast.GetTranslationUnitDecl()
+ : containing_decl_ctx,
+ GetOwningClangModule(die), attrs.name.GetStringRef(), clang_type,
+ attrs.storage, attrs.is_inline);
+ clang::FunctionTemplateDecl *func_template_decl =
+ m_ast.CreateFunctionTemplateDecl(
+ containing_decl_ctx, GetOwningClangModule(die),
+ template_function_decl, template_param_infos);
+ m_ast.CreateFunctionTemplateSpecializationInfo(
+ template_function_decl, func_template_decl, template_param_infos);
+ }
+
+ lldbassert(function_decl);
+
+ if (function_decl) {
+ // Attach an asm(<mangled_name>) label to the FunctionDecl.
+ // This ensures that clang::CodeGen emits function calls
+ // using symbols that are mangled according to the DW_AT_linkage_name.
+ // If we didn't do this, the external symbols wouldn't exactly
+ // match the mangled name LLDB knows about and the IRExecutionUnit
+ // would have to fall back to searching object files for
+ // approximately matching function names. The motivating
+ // example is generating calls to ABI-tagged template functions.
+ // This is done separately for member functions in
+ // AddMethodToCXXRecordType.
+ if (attrs.mangled_name)
+ function_decl->addAttr(clang::AsmLabelAttr::CreateImplicit(
+ m_ast.getASTContext(), attrs.mangled_name, /*literal=*/false));
+
+ LinkDeclContextToDIE(function_decl, die);
+
+ if (!function_param_decls.empty()) {
+ m_ast.SetFunctionParameters(function_decl, function_param_decls);
+ if (template_function_decl)
+ m_ast.SetFunctionParameters(template_function_decl,
+ function_param_decls);
+ }
+
+ ClangASTMetadata metadata;
+ metadata.SetUserID(die.GetID());
+
+ char const *object_pointer_name =
+ attrs.object_pointer ? attrs.object_pointer.GetName() : nullptr;
+ if (object_pointer_name) {
+ metadata.SetObjectPtrName(object_pointer_name);
+ LLDB_LOGF(log,
+ "Setting object pointer name: %s on function "
+ "object %p.",
+ object_pointer_name, static_cast<void *>(function_decl));
+ }
+ m_ast.SetMetadata(function_decl, metadata);
+ }
+ }
+ }
+ }
+ return dwarf->MakeType(
+ die.GetID(), attrs.name, std::nullopt, nullptr, LLDB_INVALID_UID,
+ Type::eEncodingIsUID, &attrs.decl, clang_type, Type::ResolveState::Full);
+}
+
+TypeSP
+DWARFASTParserClang::ParseArrayType(const DWARFDIE &die,
+ const ParsedDWARFTypeAttributes &attrs) {
+ SymbolFileDWARF *dwarf = die.GetDWARF();
+
+ DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(),
+ DW_TAG_value_to_name(tag), type_name_cstr);
+
+ DWARFDIE type_die = attrs.type.Reference();
+ Type *element_type = dwarf->ResolveTypeUID(type_die, true);
+
+ if (!element_type)
+ return nullptr;
+
+ std::optional<SymbolFile::ArrayInfo> array_info = ParseChildArrayInfo(die);
+ uint32_t byte_stride = attrs.byte_stride;
+ uint32_t bit_stride = attrs.bit_stride;
+ if (array_info) {
+ byte_stride = array_info->byte_stride;
+ bit_stride = array_info->bit_stride;
+ }
+ if (byte_stride == 0 && bit_stride == 0)
+ byte_stride = element_type->GetByteSize(nullptr).value_or(0);
+ CompilerType array_element_type = element_type->GetForwardCompilerType();
+ TypeSystemClang::RequireCompleteType(array_element_type);
+
+ uint64_t array_element_bit_stride = byte_stride * 8 + bit_stride;
+ CompilerType clang_type;
+ if (array_info && array_info->element_orders.size() > 0) {
+ uint64_t num_elements = 0;
+ auto end = array_info->element_orders.rend();
+ for (auto pos = array_info->element_orders.rbegin(); pos != end; ++pos) {
+ num_elements = *pos;
+ clang_type = m_ast.CreateArrayType(array_element_type, num_elements,
+ attrs.is_vector);
+ array_element_type = clang_type;
+ array_element_bit_stride = num_elements
+ ? array_element_bit_stride * num_elements
+ : array_element_bit_stride;
+ }
+ } else {
+ clang_type =
+ m_ast.CreateArrayType(array_element_type, 0, attrs.is_vector);
+ }
+ ConstString empty_name;
+ TypeSP type_sp =
+ dwarf->MakeType(die.GetID(), empty_name, array_element_bit_stride / 8,
+ nullptr, type_die.GetID(), Type::eEncodingIsUID,
+ &attrs.decl, clang_type, Type::ResolveState::Full);
+ type_sp->SetEncodingType(element_type);
+ const clang::Type *type = ClangUtil::GetQualType(clang_type).getTypePtr();
+ m_ast.SetMetadataAsUserID(type, die.GetID());
+ return type_sp;
+}
+
+TypeSP DWARFASTParserClang::ParsePointerToMemberType(
+ const DWARFDIE &die, const ParsedDWARFTypeAttributes &attrs) {
+ SymbolFileDWARF *dwarf = die.GetDWARF();
+ Type *pointee_type = dwarf->ResolveTypeUID(attrs.type.Reference(), true);
+ Type *class_type =
+ dwarf->ResolveTypeUID(attrs.containing_type.Reference(), true);
+
+ // Check to make sure pointers are not NULL before attempting to
+ // dereference them.
+ if ((class_type == nullptr) || (pointee_type == nullptr))
+ return nullptr;
+
+ CompilerType pointee_clang_type = pointee_type->GetForwardCompilerType();
+ CompilerType class_clang_type = class_type->GetForwardCompilerType();
+
+ CompilerType clang_type = TypeSystemClang::CreateMemberPointerType(
+ class_clang_type, pointee_clang_type);
+
+ if (std::optional<uint64_t> clang_type_size =
+ clang_type.GetByteSize(nullptr)) {
+ return dwarf->MakeType(die.GetID(), attrs.name, *clang_type_size, nullptr,
+ LLDB_INVALID_UID, Type::eEncodingIsUID, nullptr,
+ clang_type, Type::ResolveState::Forward);
+ }
+ return nullptr;
+}
+
+void DWARFASTParserClang::ParseInheritance(
+ const DWARFDIE &die, const DWARFDIE &parent_die,
+ const CompilerType class_clang_type, const AccessType default_accessibility,
+ const lldb::ModuleSP &module_sp,
+ std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> &base_classes,
+ ClangASTImporter::LayoutInfo &layout_info) {
+ auto ast =
+ class_clang_type.GetTypeSystem().dyn_cast_or_null<TypeSystemClang>();
+ if (ast == nullptr)
+ return;
+
+ // TODO: implement DW_TAG_inheritance type parsing.
+ DWARFAttributes attributes = die.GetAttributes();
+ if (attributes.Size() == 0)
+ return;
+
+ DWARFFormValue encoding_form;
+ AccessType accessibility = default_accessibility;
+ bool is_virtual = false;
+ bool is_base_of_class = true;
+ off_t member_byte_offset = 0;
+
+ for (uint32_t i = 0; i < attributes.Size(); ++i) {
+ const dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(i, form_value)) {
+ switch (attr) {
+ case DW_AT_type:
+ encoding_form = form_value;
+ break;
+ case DW_AT_data_member_location:
+ if (auto maybe_offset =
+ ExtractDataMemberLocation(die, form_value, module_sp))
+ member_byte_offset = *maybe_offset;
+ break;
+
+ case DW_AT_accessibility:
+ accessibility =
+ DWARFASTParser::GetAccessTypeFromDWARF(form_value.Unsigned());
+ break;
+
+ case DW_AT_virtuality:
+ is_virtual = form_value.Boolean();
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ Type *base_class_type = die.ResolveTypeUID(encoding_form.Reference());
+ if (base_class_type == nullptr) {
+ module_sp->ReportError("{0:x16}: DW_TAG_inheritance failed to "
+ "resolve the base class at {1:x16}"
+ " from enclosing type {2:x16}. \nPlease file "
+ "a bug and attach the file at the start of "
+ "this error message",
+ die.GetOffset(),
+ encoding_form.Reference().GetOffset(),
+ parent_die.GetOffset());
+ return;
+ }
+
+ CompilerType base_class_clang_type = base_class_type->GetFullCompilerType();
+ assert(base_class_clang_type);
+ if (TypeSystemClang::IsObjCObjectOrInterfaceType(class_clang_type)) {
+ ast->SetObjCSuperClass(class_clang_type, base_class_clang_type);
+ return;
+ }
+ std::unique_ptr<clang::CXXBaseSpecifier> result =
+ ast->CreateBaseClassSpecifier(base_class_clang_type.GetOpaqueQualType(),
+ accessibility, is_virtual,
+ is_base_of_class);
+ if (!result)
+ return;
+
+ base_classes.push_back(std::move(result));
+
+ if (is_virtual) {
+ // Do not specify any offset for virtual inheritance. The DWARF
+ // produced by clang doesn't give us a constant offset, but gives
+ // us a DWARF expressions that requires an actual object in memory.
+ // the DW_AT_data_member_location for a virtual base class looks
+ // like:
+ // DW_AT_data_member_location( DW_OP_dup, DW_OP_deref,
+ // DW_OP_constu(0x00000018), DW_OP_minus, DW_OP_deref,
+ // DW_OP_plus )
+ // Given this, there is really no valid response we can give to
+ // clang for virtual base class offsets, and this should eventually
+ // be removed from LayoutRecordType() in the external
+ // AST source in clang.
+ } else {
+ layout_info.base_offsets.insert(std::make_pair(
+ ast->GetAsCXXRecordDecl(base_class_clang_type.GetOpaqueQualType()),
+ clang::CharUnits::fromQuantity(member_byte_offset)));
+ }
+}
+
+TypeSP DWARFASTParserClang::UpdateSymbolContextScopeForType(
+ const SymbolContext &sc, const DWARFDIE &die, TypeSP type_sp) {
+ if (!type_sp)
+ return type_sp;
+
+ DWARFDIE sc_parent_die = SymbolFileDWARF::GetParentSymbolContextDIE(die);
+ dw_tag_t sc_parent_tag = sc_parent_die.Tag();
+
+ SymbolContextScope *symbol_context_scope = nullptr;
+ if (sc_parent_tag == DW_TAG_compile_unit ||
+ sc_parent_tag == DW_TAG_partial_unit) {
+ symbol_context_scope = sc.comp_unit;
+ } else if (sc.function != nullptr && sc_parent_die) {
+ symbol_context_scope =
+ sc.function->GetBlock(true).FindBlockByID(sc_parent_die.GetID());
+ if (symbol_context_scope == nullptr)
+ symbol_context_scope = sc.function;
+ } else {
+ symbol_context_scope = sc.module_sp.get();
+ }
+
+ if (symbol_context_scope != nullptr)
+ type_sp->SetSymbolContextScope(symbol_context_scope);
+ return type_sp;
+}
+
+void DWARFASTParserClang::GetUniqueTypeNameAndDeclaration(
+ const lldb_private::plugin::dwarf::DWARFDIE &die,
+ lldb::LanguageType language, lldb_private::ConstString &unique_typename,
+ lldb_private::Declaration &decl_declaration) {
+ // For C++, we rely solely upon the one definition rule that says
+ // only one thing can exist at a given decl context. We ignore the
+ // file and line that things are declared on.
+ if (!die.IsValid() || !Language::LanguageIsCPlusPlus(language) ||
+ unique_typename.IsEmpty())
+ return;
+ decl_declaration.Clear();
+ std::string qualified_name;
+ DWARFDIE parent_decl_ctx_die = die.GetParentDeclContextDIE();
+ // TODO: change this to get the correct decl context parent....
+ while (parent_decl_ctx_die) {
+ // The name may not contain template parameters due to
+ // -gsimple-template-names; we must reconstruct the full name from child
+ // template parameter dies via GetDIEClassTemplateParams().
+ const dw_tag_t parent_tag = parent_decl_ctx_die.Tag();
+ switch (parent_tag) {
+ case DW_TAG_namespace: {
+ if (const char *namespace_name = parent_decl_ctx_die.GetName()) {
+ qualified_name.insert(0, "::");
+ qualified_name.insert(0, namespace_name);
+ } else {
+ qualified_name.insert(0, "(anonymous namespace)::");
+ }
+ parent_decl_ctx_die = parent_decl_ctx_die.GetParentDeclContextDIE();
+ break;
+ }
+
+ case DW_TAG_class_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type: {
+ if (const char *class_union_struct_name = parent_decl_ctx_die.GetName()) {
+ qualified_name.insert(
+ 0, GetDIEClassTemplateParams(parent_decl_ctx_die));
+ qualified_name.insert(0, "::");
+ qualified_name.insert(0, class_union_struct_name);
+ }
+ parent_decl_ctx_die = parent_decl_ctx_die.GetParentDeclContextDIE();
+ break;
+ }
+
+ default:
+ parent_decl_ctx_die.Clear();
+ break;
+ }
+ }
+
+ if (qualified_name.empty())
+ qualified_name.append("::");
+
+ qualified_name.append(unique_typename.GetCString());
+ qualified_name.append(GetDIEClassTemplateParams(die));
+
+ unique_typename = ConstString(qualified_name);
+}
+
+TypeSP
+DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
+ const DWARFDIE &die,
+ ParsedDWARFTypeAttributes &attrs) {
+ CompilerType clang_type;
+ const dw_tag_t tag = die.Tag();
+ SymbolFileDWARF *dwarf = die.GetDWARF();
+ LanguageType cu_language = SymbolFileDWARF::GetLanguage(*die.GetCU());
+ Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups);
+
+ ConstString unique_typename(attrs.name);
+ Declaration unique_decl(attrs.decl);
+ uint64_t byte_size = attrs.byte_size.value_or(0);
+ if (attrs.byte_size && *attrs.byte_size == 0 && attrs.name &&
+ !die.HasChildren() && cu_language == eLanguageTypeObjC) {
+ // Work around an issue with clang at the moment where forward
+ // declarations for objective C classes are emitted as:
+ // DW_TAG_structure_type [2]
+ // DW_AT_name( "ForwardObjcClass" )
+ // DW_AT_byte_size( 0x00 )
+ // DW_AT_decl_file( "..." )
+ // DW_AT_decl_line( 1 )
+ //
+ // Note that there is no DW_AT_declaration and there are no children,
+ // and the byte size is zero.
+ attrs.is_forward_declaration = true;
+ }
+
+ if (attrs.name) {
+ GetUniqueTypeNameAndDeclaration(die, cu_language, unique_typename,
+ unique_decl);
+ if (UniqueDWARFASTType *unique_ast_entry_type =
+ dwarf->GetUniqueDWARFASTTypeMap().Find(
+ unique_typename, die, unique_decl, byte_size,
+ attrs.is_forward_declaration)) {
+ if (TypeSP type_sp = unique_ast_entry_type->m_type_sp) {
+ dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get();
+ LinkDeclContextToDIE(
+ GetCachedClangDeclContextForDIE(unique_ast_entry_type->m_die), die);
+ // If the DIE being parsed in this function is a definition and the
+ // entry in the map is a declaration, then we need to update the entry
+ // to point to the definition DIE.
+ if (!attrs.is_forward_declaration &&
+ unique_ast_entry_type->m_is_forward_declaration) {
+ unique_ast_entry_type->UpdateToDefDIE(die, unique_decl, byte_size);
+ clang_type = type_sp->GetForwardCompilerType();
+
+ CompilerType compiler_type_no_qualifiers =
+ ClangUtil::RemoveFastQualifiers(clang_type);
+ dwarf->GetForwardDeclCompilerTypeToDIE().insert_or_assign(
+ compiler_type_no_qualifiers.GetOpaqueQualType(),
+ *die.GetDIERef());
+ }
+ return type_sp;
+ }
+ }
+ }
+
+ DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(),
+ DW_TAG_value_to_name(tag), type_name_cstr);
+
+ int tag_decl_kind = -1;
+ AccessType default_accessibility = eAccessNone;
+ if (tag == DW_TAG_structure_type) {
+ tag_decl_kind = llvm::to_underlying(clang::TagTypeKind::Struct);
+ default_accessibility = eAccessPublic;
+ } else if (tag == DW_TAG_union_type) {
+ tag_decl_kind = llvm::to_underlying(clang::TagTypeKind::Union);
+ default_accessibility = eAccessPublic;
+ } else if (tag == DW_TAG_class_type) {
+ tag_decl_kind = llvm::to_underlying(clang::TagTypeKind::Class);
+ default_accessibility = eAccessPrivate;
+ }
+
+ if ((attrs.class_language == eLanguageTypeObjC ||
+ attrs.class_language == eLanguageTypeObjC_plus_plus) &&
+ !attrs.is_complete_objc_class &&
+ die.Supports_DW_AT_APPLE_objc_complete_type()) {
+ // We have a valid eSymbolTypeObjCClass class symbol whose name
+ // matches the current objective C class that we are trying to find
+ // and this DIE isn't the complete definition (we checked
+ // is_complete_objc_class above and know it is false), so the real
+ // definition is in here somewhere
+ TypeSP type_sp =
+ dwarf->FindCompleteObjCDefinitionTypeForDIE(die, attrs.name, true);
+
+ if (!type_sp) {
+ SymbolFileDWARFDebugMap *debug_map_symfile = dwarf->GetDebugMapSymfile();
+ if (debug_map_symfile) {
+ // We weren't able to find a full declaration in this DWARF,
+ // see if we have a declaration anywhere else...
+ type_sp = debug_map_symfile->FindCompleteObjCDefinitionTypeForDIE(
+ die, attrs.name, true);
+ }
+ }
+
+ if (type_sp) {
+ if (log) {
+ dwarf->GetObjectFile()->GetModule()->LogMessage(
+ log,
+ "SymbolFileDWARF({0:p}) - {1:x16}: {2} ({3}) type \"{4}\" is an "
+ "incomplete objc type, complete type is {5:x8}",
+ static_cast<void *>(this), die.GetID(), DW_TAG_value_to_name(tag),
+ tag, attrs.name.GetCString(), type_sp->GetID());
+ }
+ return type_sp;
+ }
+ }
+
+ if (attrs.is_forward_declaration) {
+ // See if the type comes from a Clang module and if so, track down
+ // that type.
+ TypeSP type_sp = ParseTypeFromClangModule(sc, die, log);
+ if (type_sp)
+ return type_sp;
+ }
+
+ assert(tag_decl_kind != -1);
+ UNUSED_IF_ASSERT_DISABLED(tag_decl_kind);
+ clang::DeclContext *containing_decl_ctx =
+ GetClangDeclContextContainingDIE(die, nullptr);
+
+ PrepareContextToReceiveMembers(m_ast, GetClangASTImporter(),
+ containing_decl_ctx, die,
+ attrs.name.GetCString());
+
+ if (attrs.accessibility == eAccessNone && containing_decl_ctx) {
+ // Check the decl context that contains this class/struct/union. If
+ // it is a class we must give it an accessibility.
+ const clang::Decl::Kind containing_decl_kind =
+ containing_decl_ctx->getDeclKind();
+ if (DeclKindIsCXXClass(containing_decl_kind))
+ attrs.accessibility = default_accessibility;
+ }
+
+ ClangASTMetadata metadata;
+ metadata.SetUserID(die.GetID());
+ metadata.SetIsDynamicCXXType(dwarf->ClassOrStructIsVirtual(die));
+
+ TypeSystemClang::TemplateParameterInfos template_param_infos;
+ if (ParseTemplateParameterInfos(die, template_param_infos)) {
+ clang::ClassTemplateDecl *class_template_decl =
+ m_ast.ParseClassTemplateDecl(
+ containing_decl_ctx, GetOwningClangModule(die), attrs.accessibility,
+ attrs.name.GetCString(), tag_decl_kind, template_param_infos);
+ if (!class_template_decl) {
+ if (log) {
+ dwarf->GetObjectFile()->GetModule()->LogMessage(
+ log,
+ "SymbolFileDWARF({0:p}) - {1:x16}: {2} ({3}) type \"{4}\" "
+ "clang::ClassTemplateDecl failed to return a decl.",
+ static_cast<void *>(this), die.GetID(), DW_TAG_value_to_name(tag),
+ tag, attrs.name.GetCString());
+ }
+ return TypeSP();
+ }
+
+ clang::ClassTemplateSpecializationDecl *class_specialization_decl =
+ m_ast.CreateClassTemplateSpecializationDecl(
+ containing_decl_ctx, GetOwningClangModule(die), class_template_decl,
+ tag_decl_kind, template_param_infos);
+ clang_type =
+ m_ast.CreateClassTemplateSpecializationType(class_specialization_decl);
+
+ m_ast.SetMetadata(class_template_decl, metadata);
+ m_ast.SetMetadata(class_specialization_decl, metadata);
+ }
+
+ if (!clang_type) {
+ clang_type = m_ast.CreateRecordType(
+ containing_decl_ctx, GetOwningClangModule(die), attrs.accessibility,
+ attrs.name.GetCString(), tag_decl_kind, attrs.class_language, &metadata,
+ attrs.exports_symbols);
+ }
+
+ TypeSP type_sp = dwarf->MakeType(
+ die.GetID(), attrs.name, attrs.byte_size, nullptr, LLDB_INVALID_UID,
+ Type::eEncodingIsUID, &attrs.decl, clang_type,
+ Type::ResolveState::Forward,
+ TypePayloadClang(OptionalClangModuleID(), attrs.is_complete_objc_class));
+
+ // Store a forward declaration to this class type in case any
+ // parameters in any class methods need it for the clang types for
+ // function prototypes.
+ clang::DeclContext *type_decl_ctx =
+ TypeSystemClang::GetDeclContextForType(clang_type);
+ LinkDeclContextToDIE(type_decl_ctx, die);
+
+ // UniqueDWARFASTType is large, so don't create a local variables on the
+ // stack, put it on the heap. This function is often called recursively and
+ // clang isn't good at sharing the stack space for variables in different
+ // blocks.
+ auto unique_ast_entry_up = std::make_unique<UniqueDWARFASTType>();
+ // Add our type to the unique type map so we don't end up creating many
+ // copies of the same type over and over in the ASTContext for our
+ // module
+ unique_ast_entry_up->m_type_sp = type_sp;
+ unique_ast_entry_up->m_die = die;
+ unique_ast_entry_up->m_declaration = unique_decl;
+ unique_ast_entry_up->m_byte_size = byte_size;
+ unique_ast_entry_up->m_is_forward_declaration = attrs.is_forward_declaration;
+ dwarf->GetUniqueDWARFASTTypeMap().Insert(unique_typename,
+ *unique_ast_entry_up);
+
+ // Leave this as a forward declaration until we need to know the
+ // details of the type. lldb_private::Type will automatically call
+ // the SymbolFile virtual function
+ // "SymbolFileDWARF::CompleteType(Type *)" When the definition
+ // needs to be defined.
+ bool inserted =
+ dwarf->GetForwardDeclCompilerTypeToDIE()
+ .try_emplace(
+ ClangUtil::RemoveFastQualifiers(clang_type).GetOpaqueQualType(),
+ *die.GetDIERef())
+ .second;
+ assert(inserted && "Type already in the forward declaration map!");
+ (void)inserted;
+ m_ast.SetHasExternalStorage(clang_type.GetOpaqueQualType(), true);
+
+ // If we made a clang type, set the trivial abi if applicable: We only
+ // do this for pass by value - which implies the Trivial ABI. There
+ // isn't a way to assert that something that would normally be pass by
+ // value is pass by reference, so we ignore that attribute if set.
+ if (attrs.calling_convention == llvm::dwarf::DW_CC_pass_by_value) {
+ clang::CXXRecordDecl *record_decl =
+ m_ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType());
+ if (record_decl && record_decl->getDefinition()) {
+ record_decl->setHasTrivialSpecialMemberForCall();
+ }
+ }
+
+ if (attrs.calling_convention == llvm::dwarf::DW_CC_pass_by_reference) {
+ clang::CXXRecordDecl *record_decl =
+ m_ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType());
+ if (record_decl)
+ record_decl->setArgPassingRestrictions(
+ clang::RecordArgPassingKind::CannotPassInRegs);
+ }
+ return type_sp;
+}
+
+// DWARF parsing functions
+
+class DWARFASTParserClang::DelayedAddObjCClassProperty {
+public:
+ DelayedAddObjCClassProperty(
+ const CompilerType &class_opaque_type, const char *property_name,
+ const CompilerType &property_opaque_type, // The property type is only
+ // required if you don't have an
+ // ivar decl
+ const char *property_setter_name, const char *property_getter_name,
+ uint32_t property_attributes, const ClangASTMetadata *metadata)
+ : m_class_opaque_type(class_opaque_type), m_property_name(property_name),
+ m_property_opaque_type(property_opaque_type),
+ m_property_setter_name(property_setter_name),
+ m_property_getter_name(property_getter_name),
+ m_property_attributes(property_attributes) {
+ if (metadata != nullptr) {
+ m_metadata_up = std::make_unique<ClangASTMetadata>();
+ *m_metadata_up = *metadata;
+ }
+ }
+
+ DelayedAddObjCClassProperty(const DelayedAddObjCClassProperty &rhs) {
+ *this = rhs;
+ }
+
+ DelayedAddObjCClassProperty &
+ operator=(const DelayedAddObjCClassProperty &rhs) {
+ m_class_opaque_type = rhs.m_class_opaque_type;
+ m_property_name = rhs.m_property_name;
+ m_property_opaque_type = rhs.m_property_opaque_type;
+ m_property_setter_name = rhs.m_property_setter_name;
+ m_property_getter_name = rhs.m_property_getter_name;
+ m_property_attributes = rhs.m_property_attributes;
+
+ if (rhs.m_metadata_up) {
+ m_metadata_up = std::make_unique<ClangASTMetadata>();
+ *m_metadata_up = *rhs.m_metadata_up;
+ }
+ return *this;
+ }
+
+ bool Finalize() {
+ return TypeSystemClang::AddObjCClassProperty(
+ m_class_opaque_type, m_property_name, m_property_opaque_type,
+ /*ivar_decl=*/nullptr, m_property_setter_name, m_property_getter_name,
+ m_property_attributes, m_metadata_up.get());
+ }
+
+private:
+ CompilerType m_class_opaque_type;
+ const char *m_property_name;
+ CompilerType m_property_opaque_type;
+ const char *m_property_setter_name;
+ const char *m_property_getter_name;
+ uint32_t m_property_attributes;
+ std::unique_ptr<ClangASTMetadata> m_metadata_up;
+};
+
+bool DWARFASTParserClang::ParseTemplateDIE(
+ const DWARFDIE &die,
+ TypeSystemClang::TemplateParameterInfos &template_param_infos) {
+ const dw_tag_t tag = die.Tag();
+ bool is_template_template_argument = false;
+
+ switch (tag) {
+ case DW_TAG_GNU_template_parameter_pack: {
+ template_param_infos.SetParameterPack(
+ std::make_unique<TypeSystemClang::TemplateParameterInfos>());
+ for (DWARFDIE child_die : die.children()) {
+ if (!ParseTemplateDIE(child_die, template_param_infos.GetParameterPack()))
+ return false;
+ }
+ if (const char *name = die.GetName()) {
+ template_param_infos.SetPackName(name);
+ }
+ return true;
+ }
+ case DW_TAG_GNU_template_template_param:
+ is_template_template_argument = true;
+ [[fallthrough]];
+ case DW_TAG_template_type_parameter:
+ case DW_TAG_template_value_parameter: {
+ DWARFAttributes attributes = die.GetAttributes();
+ if (attributes.Size() == 0)
+ return true;
+
+ const char *name = nullptr;
+ const char *template_name = nullptr;
+ CompilerType clang_type;
+ uint64_t uval64 = 0;
+ bool uval64_valid = false;
+ bool is_default_template_arg = false;
+ DWARFFormValue form_value;
+ for (size_t i = 0; i < attributes.Size(); ++i) {
+ const dw_attr_t attr = attributes.AttributeAtIndex(i);
+
+ switch (attr) {
+ case DW_AT_name:
+ if (attributes.ExtractFormValueAtIndex(i, form_value))
+ name = form_value.AsCString();
+ break;
+
+ case DW_AT_GNU_template_name:
+ if (attributes.ExtractFormValueAtIndex(i, form_value))
+ template_name = form_value.AsCString();
+ break;
+
+ case DW_AT_type:
+ if (attributes.ExtractFormValueAtIndex(i, form_value)) {
+ Type *lldb_type = die.ResolveTypeUID(form_value.Reference());
+ if (lldb_type)
+ clang_type = lldb_type->GetForwardCompilerType();
+ }
+ break;
+
+ case DW_AT_const_value:
+ if (attributes.ExtractFormValueAtIndex(i, form_value)) {
+ uval64_valid = true;
+ uval64 = form_value.Unsigned();
+ }
+ break;
+ case DW_AT_default_value:
+ if (attributes.ExtractFormValueAtIndex(i, form_value))
+ is_default_template_arg = form_value.Boolean();
+ break;
+ default:
+ break;
+ }
+ }
+
+ clang::ASTContext &ast = m_ast.getASTContext();
+ if (!clang_type)
+ clang_type = m_ast.GetBasicType(eBasicTypeVoid);
+
+ if (!is_template_template_argument) {
+ bool is_signed = false;
+ // Get the signed value for any integer or enumeration if available
+ clang_type.IsIntegerOrEnumerationType(is_signed);
+
+ if (name && !name[0])
+ name = nullptr;
+
+ if (tag == DW_TAG_template_value_parameter && uval64_valid) {
+ std::optional<uint64_t> size = clang_type.GetBitSize(nullptr);
+ if (!size)
+ return false;
+ llvm::APInt apint(*size, uval64, is_signed);
+ template_param_infos.InsertArg(
+ name, clang::TemplateArgument(ast, llvm::APSInt(apint, !is_signed),
+ ClangUtil::GetQualType(clang_type),
+ is_default_template_arg));
+ } else {
+ template_param_infos.InsertArg(
+ name, clang::TemplateArgument(ClangUtil::GetQualType(clang_type),
+ /*isNullPtr*/ false,
+ is_default_template_arg));
+ }
+ } else {
+ auto *tplt_type = m_ast.CreateTemplateTemplateParmDecl(template_name);
+ template_param_infos.InsertArg(
+ name, clang::TemplateArgument(clang::TemplateName(tplt_type),
+ is_default_template_arg));
+ }
+ }
+ return true;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+bool DWARFASTParserClang::ParseTemplateParameterInfos(
+ const DWARFDIE &parent_die,
+ TypeSystemClang::TemplateParameterInfos &template_param_infos) {
+
+ if (!parent_die)
+ return false;
+
+ for (DWARFDIE die : parent_die.children()) {
+ const dw_tag_t tag = die.Tag();
+
+ switch (tag) {
+ case DW_TAG_template_type_parameter:
+ case DW_TAG_template_value_parameter:
+ case DW_TAG_GNU_template_parameter_pack:
+ case DW_TAG_GNU_template_template_param:
+ ParseTemplateDIE(die, template_param_infos);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return !template_param_infos.IsEmpty() ||
+ template_param_infos.hasParameterPack();
+}
+
+bool DWARFASTParserClang::CompleteRecordType(const DWARFDIE &die,
+ lldb_private::Type *type,
+ CompilerType &clang_type) {
+ const dw_tag_t tag = die.Tag();
+ SymbolFileDWARF *dwarf = die.GetDWARF();
+
+ ClangASTImporter::LayoutInfo layout_info;
+ std::vector<DWARFDIE> contained_type_dies;
+
+ if (die.GetAttributeValueAsUnsigned(DW_AT_declaration, 0))
+ return false; // No definition, cannot complete.
+
+ // Start the definition if the type is not being defined already. This can
+ // happen (e.g.) when adding nested types to a class type -- see
+ // PrepareContextToReceiveMembers.
+ if (!clang_type.IsBeingDefined())
+ TypeSystemClang::StartTagDeclarationDefinition(clang_type);
+
+ AccessType default_accessibility = eAccessNone;
+ if (tag == DW_TAG_structure_type) {
+ default_accessibility = eAccessPublic;
+ } else if (tag == DW_TAG_union_type) {
+ default_accessibility = eAccessPublic;
+ } else if (tag == DW_TAG_class_type) {
+ default_accessibility = eAccessPrivate;
+ }
+
+ std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> bases;
+ // Parse members and base classes first
+ std::vector<DWARFDIE> member_function_dies;
+
+ DelayedPropertyList delayed_properties;
+ ParseChildMembers(die, clang_type, bases, member_function_dies,
+ contained_type_dies, delayed_properties,
+ default_accessibility, layout_info);
+
+ // Now parse any methods if there were any...
+ for (const DWARFDIE &die : member_function_dies)
+ dwarf->ResolveType(die);
+
+ if (TypeSystemClang::IsObjCObjectOrInterfaceType(clang_type)) {
+ ConstString class_name(clang_type.GetTypeName());
+ if (class_name) {
+ dwarf->GetObjCMethods(class_name, [&](DWARFDIE method_die) {
+ method_die.ResolveType();
+ return true;
+ });
+
+ for (DelayedAddObjCClassProperty &property : delayed_properties)
+ property.Finalize();
+ }
+ }
+
+ if (!bases.empty()) {
+ // Make sure all base classes refer to complete types and not forward
+ // declarations. If we don't do this, clang will crash with an
+ // assertion in the call to clang_type.TransferBaseClasses()
+ for (const auto &base_class : bases) {
+ clang::TypeSourceInfo *type_source_info = base_class->getTypeSourceInfo();
+ if (type_source_info)
+ TypeSystemClang::RequireCompleteType(
+ m_ast.GetType(type_source_info->getType()));
+ }
+
+ m_ast.TransferBaseClasses(clang_type.GetOpaqueQualType(), std::move(bases));
+ }
+
+ m_ast.AddMethodOverridesForCXXRecordType(clang_type.GetOpaqueQualType());
+ TypeSystemClang::BuildIndirectFields(clang_type);
+ TypeSystemClang::CompleteTagDeclarationDefinition(clang_type);
+
+ if (type)
+ layout_info.bit_size = type->GetByteSize(nullptr).value_or(0) * 8;
+ if (layout_info.bit_size == 0)
+ layout_info.bit_size =
+ die.GetAttributeValueAsUnsigned(DW_AT_byte_size, 0) * 8;
+ if (layout_info.alignment == 0)
+ layout_info.alignment =
+ die.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_alignment, 0) * 8;
+
+ clang::CXXRecordDecl *record_decl =
+ m_ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType());
+ if (record_decl)
+ GetClangASTImporter().SetRecordLayout(record_decl, layout_info);
+
+ // Now parse all contained types inside of the class. We make forward
+ // declarations to all classes, but we need the CXXRecordDecl to have decls
+ // for all contained types because we don't get asked for them via the
+ // external AST support.
+ for (const DWARFDIE &die : contained_type_dies)
+ dwarf->ResolveType(die);
+
+ return (bool)clang_type;
+}
+
+bool DWARFASTParserClang::CompleteEnumType(const DWARFDIE &die,
+ lldb_private::Type *type,
+ CompilerType &clang_type) {
+ if (TypeSystemClang::StartTagDeclarationDefinition(clang_type)) {
+ if (die.HasChildren()) {
+ bool is_signed = false;
+ clang_type.IsIntegerType(is_signed);
+ ParseChildEnumerators(clang_type, is_signed,
+ type->GetByteSize(nullptr).value_or(0), die);
+ }
+ TypeSystemClang::CompleteTagDeclarationDefinition(clang_type);
+ }
+ return (bool)clang_type;
+}
+
+bool DWARFASTParserClang::CompleteTypeFromDWARF(const DWARFDIE &die,
+ lldb_private::Type *type,
+ CompilerType &clang_type) {
+ SymbolFileDWARF *dwarf = die.GetDWARF();
+
+ std::lock_guard<std::recursive_mutex> guard(
+ dwarf->GetObjectFile()->GetModule()->GetMutex());
+
+ // Disable external storage for this type so we don't get anymore
+ // clang::ExternalASTSource queries for this type.
+ m_ast.SetHasExternalStorage(clang_type.GetOpaqueQualType(), false);
+
+ if (!die)
+ return false;
+
+ const dw_tag_t tag = die.Tag();
+
+ assert(clang_type);
+ switch (tag) {
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_class_type:
+ CompleteRecordType(die, type, clang_type);
+ break;
+ case DW_TAG_enumeration_type:
+ CompleteEnumType(die, type, clang_type);
+ break;
+ default:
+ assert(false && "not a forward clang type decl!");
+ break;
+ }
+
+ // If the type is still not fully defined at this point, it means we weren't
+ // able to find its definition. We must forcefully complete it to preserve
+ // clang AST invariants.
+ if (clang_type.IsBeingDefined()) {
+ TypeSystemClang::CompleteTagDeclarationDefinition(clang_type);
+ m_ast.SetDeclIsForcefullyCompleted(ClangUtil::GetAsTagDecl(clang_type));
+ }
+
+ return true;
+}
+
+void DWARFASTParserClang::EnsureAllDIEsInDeclContextHaveBeenParsed(
+ lldb_private::CompilerDeclContext decl_context) {
+ auto opaque_decl_ctx =
+ (clang::DeclContext *)decl_context.GetOpaqueDeclContext();
+ for (auto it = m_decl_ctx_to_die.find(opaque_decl_ctx);
+ it != m_decl_ctx_to_die.end() && it->first == opaque_decl_ctx;
+ it = m_decl_ctx_to_die.erase(it))
+ for (DWARFDIE decl : it->second.children())
+ GetClangDeclForDIE(decl);
+}
+
+CompilerDecl DWARFASTParserClang::GetDeclForUIDFromDWARF(const DWARFDIE &die) {
+ clang::Decl *clang_decl = GetClangDeclForDIE(die);
+ if (clang_decl != nullptr)
+ return m_ast.GetCompilerDecl(clang_decl);
+ return {};
+}
+
+CompilerDeclContext
+DWARFASTParserClang::GetDeclContextForUIDFromDWARF(const DWARFDIE &die) {
+ clang::DeclContext *clang_decl_ctx = GetClangDeclContextForDIE(die);
+ if (clang_decl_ctx)
+ return m_ast.CreateDeclContext(clang_decl_ctx);
+ return {};
+}
+
+CompilerDeclContext
+DWARFASTParserClang::GetDeclContextContainingUIDFromDWARF(const DWARFDIE &die) {
+ clang::DeclContext *clang_decl_ctx =
+ GetClangDeclContextContainingDIE(die, nullptr);
+ if (clang_decl_ctx)
+ return m_ast.CreateDeclContext(clang_decl_ctx);
+ return {};
+}
+
+size_t DWARFASTParserClang::ParseChildEnumerators(
+ lldb_private::CompilerType &clang_type, bool is_signed,
+ uint32_t enumerator_byte_size, const DWARFDIE &parent_die) {
+ if (!parent_die)
+ return 0;
+
+ size_t enumerators_added = 0;
+
+ for (DWARFDIE die : parent_die.children()) {
+ const dw_tag_t tag = die.Tag();
+ if (tag != DW_TAG_enumerator)
+ continue;
+
+ DWARFAttributes attributes = die.GetAttributes();
+ if (attributes.Size() == 0)
+ continue;
+
+ const char *name = nullptr;
+ bool got_value = false;
+ int64_t enum_value = 0;
+ Declaration decl;
+
+ for (size_t i = 0; i < attributes.Size(); ++i) {
+ const dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(i, form_value)) {
+ switch (attr) {
+ case DW_AT_const_value:
+ got_value = true;
+ if (is_signed)
+ enum_value = form_value.Signed();
+ else
+ enum_value = form_value.Unsigned();
+ break;
+
+ case DW_AT_name:
+ name = form_value.AsCString();
+ break;
+
+ case DW_AT_description:
+ default:
+ case DW_AT_decl_file:
+ decl.SetFile(
+ attributes.CompileUnitAtIndex(i)->GetFile(form_value.Unsigned()));
+ break;
+ case DW_AT_decl_line:
+ decl.SetLine(form_value.Unsigned());
+ break;
+ case DW_AT_decl_column:
+ decl.SetColumn(form_value.Unsigned());
+ break;
+ case DW_AT_sibling:
+ break;
+ }
+ }
+ }
+
+ if (name && name[0] && got_value) {
+ m_ast.AddEnumerationValueToEnumerationType(
+ clang_type, decl, name, enum_value, enumerator_byte_size * 8);
+ ++enumerators_added;
+ }
+ }
+ return enumerators_added;
+}
+
+ConstString
+DWARFASTParserClang::ConstructDemangledNameFromDWARF(const DWARFDIE &die) {
+ bool is_static = false;
+ bool is_variadic = false;
+ bool has_template_params = false;
+ unsigned type_quals = 0;
+ std::vector<CompilerType> param_types;
+ std::vector<clang::ParmVarDecl *> param_decls;
+ StreamString sstr;
+
+ DWARFDeclContext decl_ctx = die.GetDWARFDeclContext();
+ sstr << decl_ctx.GetQualifiedName();
+
+ clang::DeclContext *containing_decl_ctx =
+ GetClangDeclContextContainingDIE(die, nullptr);
+ ParseChildParameters(containing_decl_ctx, die, true, is_static, is_variadic,
+ has_template_params, param_types, param_decls,
+ type_quals);
+ sstr << "(";
+ for (size_t i = 0; i < param_types.size(); i++) {
+ if (i > 0)
+ sstr << ", ";
+ sstr << param_types[i].GetTypeName();
+ }
+ if (is_variadic)
+ sstr << ", ...";
+ sstr << ")";
+ if (type_quals & clang::Qualifiers::Const)
+ sstr << " const";
+
+ return ConstString(sstr.GetString());
+}
+
+Function *
+DWARFASTParserClang::ParseFunctionFromDWARF(CompileUnit &comp_unit,
+ const DWARFDIE &die,
+ const AddressRange &func_range) {
+ assert(func_range.GetBaseAddress().IsValid());
+ DWARFRangeList func_ranges;
+ const char *name = nullptr;
+ const char *mangled = nullptr;
+ std::optional<int> decl_file;
+ std::optional<int> decl_line;
+ std::optional<int> decl_column;
+ std::optional<int> call_file;
+ std::optional<int> call_line;
+ std::optional<int> call_column;
+ DWARFExpressionList frame_base;
+
+ const dw_tag_t tag = die.Tag();
+
+ if (tag != DW_TAG_subprogram)
+ return nullptr;
+
+ if (die.GetDIENamesAndRanges(name, mangled, func_ranges, decl_file, decl_line,
+ decl_column, call_file, call_line, call_column,
+ &frame_base)) {
+ Mangled func_name;
+ if (mangled)
+ func_name.SetValue(ConstString(mangled));
+ else if ((die.GetParent().Tag() == DW_TAG_compile_unit ||
+ die.GetParent().Tag() == DW_TAG_partial_unit) &&
+ Language::LanguageIsCPlusPlus(
+ SymbolFileDWARF::GetLanguage(*die.GetCU())) &&
+ !Language::LanguageIsObjC(
+ SymbolFileDWARF::GetLanguage(*die.GetCU())) &&
+ name && strcmp(name, "main") != 0) {
+ // If the mangled name is not present in the DWARF, generate the
+ // demangled name using the decl context. We skip if the function is
+ // "main" as its name is never mangled.
+ func_name.SetValue(ConstructDemangledNameFromDWARF(die));
+ } else
+ func_name.SetValue(ConstString(name));
+
+ FunctionSP func_sp;
+ std::unique_ptr<Declaration> decl_up;
+ if (decl_file || decl_line || decl_column)
+ decl_up = std::make_unique<Declaration>(
+ die.GetCU()->GetFile(decl_file ? *decl_file : 0),
+ decl_line ? *decl_line : 0, decl_column ? *decl_column : 0);
+
+ SymbolFileDWARF *dwarf = die.GetDWARF();
+ // Supply the type _only_ if it has already been parsed
+ Type *func_type = dwarf->GetDIEToType().lookup(die.GetDIE());
+
+ assert(func_type == nullptr || func_type != DIE_IS_BEING_PARSED);
+
+ const user_id_t func_user_id = die.GetID();
+ func_sp =
+ std::make_shared<Function>(&comp_unit,
+ func_user_id, // UserID is the DIE offset
+ func_user_id, func_name, func_type,
+ func_range); // first address range
+
+ if (func_sp.get() != nullptr) {
+ if (frame_base.IsValid())
+ func_sp->GetFrameBaseExpression() = frame_base;
+ comp_unit.AddFunction(func_sp);
+ return func_sp.get();
+ }
+ }
+ return nullptr;
+}
+
+namespace {
+/// Parsed form of all attributes that are relevant for parsing Objective-C
+/// properties.
+struct PropertyAttributes {
+ explicit PropertyAttributes(const DWARFDIE &die);
+ const char *prop_name = nullptr;
+ const char *prop_getter_name = nullptr;
+ const char *prop_setter_name = nullptr;
+ /// \see clang::ObjCPropertyAttribute
+ uint32_t prop_attributes = 0;
+};
+
+struct DiscriminantValue {
+ explicit DiscriminantValue(const DWARFDIE &die, ModuleSP module_sp);
+
+ uint32_t byte_offset;
+ uint32_t byte_size;
+ DWARFFormValue type_ref;
+};
+
+struct VariantMember {
+ explicit VariantMember(DWARFDIE &die, ModuleSP module_sp);
+ bool IsDefault() const;
+
+ std::optional<uint32_t> discr_value;
+ DWARFFormValue type_ref;
+ ConstString variant_name;
+ uint32_t byte_offset;
+ ConstString GetName() const;
+};
+
+struct VariantPart {
+ explicit VariantPart(const DWARFDIE &die, const DWARFDIE &parent_die,
+ ModuleSP module_sp);
+
+ std::vector<VariantMember> &members();
+
+ DiscriminantValue &discriminant();
+
+private:
+ std::vector<VariantMember> _members;
+ DiscriminantValue _discriminant;
+};
+
+} // namespace
+
+ConstString VariantMember::GetName() const { return this->variant_name; }
+
+bool VariantMember::IsDefault() const { return !discr_value; }
+
+VariantMember::VariantMember(DWARFDIE &die, lldb::ModuleSP module_sp) {
+ assert(die.Tag() == llvm::dwarf::DW_TAG_variant);
+ this->discr_value =
+ die.GetAttributeValueAsOptionalUnsigned(DW_AT_discr_value);
+
+ for (auto child_die : die.children()) {
+ switch (child_die.Tag()) {
+ case llvm::dwarf::DW_TAG_member: {
+ DWARFAttributes attributes = child_die.GetAttributes();
+ for (std::size_t i = 0; i < attributes.Size(); ++i) {
+ DWARFFormValue form_value;
+ const dw_attr_t attr = attributes.AttributeAtIndex(i);
+ if (attributes.ExtractFormValueAtIndex(i, form_value)) {
+ switch (attr) {
+ case DW_AT_name:
+ variant_name = ConstString(form_value.AsCString());
+ break;
+ case DW_AT_type:
+ type_ref = form_value;
+ break;
+
+ case DW_AT_data_member_location:
+ if (auto maybe_offset =
+ ExtractDataMemberLocation(die, form_value, module_sp))
+ byte_offset = *maybe_offset;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+}
+
+DiscriminantValue::DiscriminantValue(const DWARFDIE &die, ModuleSP module_sp) {
+ auto referenced_die = die.GetReferencedDIE(DW_AT_discr);
+ DWARFAttributes attributes = referenced_die.GetAttributes();
+ for (std::size_t i = 0; i < attributes.Size(); ++i) {
+ const dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(i, form_value)) {
+ switch (attr) {
+ case DW_AT_type:
+ type_ref = form_value;
+ break;
+ case DW_AT_data_member_location:
+ if (auto maybe_offset =
+ ExtractDataMemberLocation(die, form_value, module_sp))
+ byte_offset = *maybe_offset;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+VariantPart::VariantPart(const DWARFDIE &die, const DWARFDIE &parent_die,
+ lldb::ModuleSP module_sp)
+ : _members(), _discriminant(die, module_sp) {
+
+ for (auto child : die.children()) {
+ if (child.Tag() == llvm::dwarf::DW_TAG_variant) {
+ _members.push_back(VariantMember(child, module_sp));
+ }
+ }
+}
+
+std::vector<VariantMember> &VariantPart::members() { return this->_members; }
+
+DiscriminantValue &VariantPart::discriminant() { return this->_discriminant; }
+
+DWARFASTParserClang::MemberAttributes::MemberAttributes(
+ const DWARFDIE &die, const DWARFDIE &parent_die, ModuleSP module_sp) {
+ DWARFAttributes attributes = die.GetAttributes();
+ for (size_t i = 0; i < attributes.Size(); ++i) {
+ const dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(i, form_value)) {
+ switch (attr) {
+ case DW_AT_name:
+ name = form_value.AsCString();
+ break;
+ case DW_AT_type:
+ encoding_form = form_value;
+ break;
+ case DW_AT_bit_offset:
+ bit_offset = form_value.Signed();
+ break;
+ case DW_AT_bit_size:
+ bit_size = form_value.Unsigned();
+ break;
+ case DW_AT_byte_size:
+ byte_size = form_value.Unsigned();
+ break;
+ case DW_AT_const_value:
+ const_value_form = form_value;
+ break;
+ case DW_AT_data_bit_offset:
+ data_bit_offset = form_value.Unsigned();
+ break;
+ case DW_AT_data_member_location:
+ if (auto maybe_offset =
+ ExtractDataMemberLocation(die, form_value, module_sp))
+ member_byte_offset = *maybe_offset;
+ break;
+
+ case DW_AT_accessibility:
+ accessibility =
+ DWARFASTParser::GetAccessTypeFromDWARF(form_value.Unsigned());
+ break;
+ case DW_AT_artificial:
+ is_artificial = form_value.Boolean();
+ break;
+ case DW_AT_declaration:
+ is_declaration = form_value.Boolean();
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ // Clang has a DWARF generation bug where sometimes it represents
+ // fields that are references with bad byte size and bit size/offset
+ // information such as:
+ //
+ // DW_AT_byte_size( 0x00 )
+ // DW_AT_bit_size( 0x40 )
+ // DW_AT_bit_offset( 0xffffffffffffffc0 )
+ //
+ // So check the bit offset to make sure it is sane, and if the values
+ // are not sane, remove them. If we don't do this then we will end up
+ // with a crash if we try to use this type in an expression when clang
+ // becomes unhappy with its recycled debug info.
+ if (byte_size.value_or(0) == 0 && bit_offset < 0) {
+ bit_size = 0;
+ bit_offset = 0;
+ }
+}
+
+PropertyAttributes::PropertyAttributes(const DWARFDIE &die) {
+
+ DWARFAttributes attributes = die.GetAttributes();
+ for (size_t i = 0; i < attributes.Size(); ++i) {
+ const dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(i, form_value)) {
+ switch (attr) {
+ case DW_AT_APPLE_property_name:
+ prop_name = form_value.AsCString();
+ break;
+ case DW_AT_APPLE_property_getter:
+ prop_getter_name = form_value.AsCString();
+ break;
+ case DW_AT_APPLE_property_setter:
+ prop_setter_name = form_value.AsCString();
+ break;
+ case DW_AT_APPLE_property_attribute:
+ prop_attributes = form_value.Unsigned();
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (!prop_name)
+ return;
+ ConstString fixed_setter;
+
+ // Check if the property getter/setter were provided as full names.
+ // We want basenames, so we extract them.
+ if (prop_getter_name && prop_getter_name[0] == '-') {
+ std::optional<const ObjCLanguage::MethodName> prop_getter_method =
+ ObjCLanguage::MethodName::Create(prop_getter_name, true);
+ if (prop_getter_method)
+ prop_getter_name =
+ ConstString(prop_getter_method->GetSelector()).GetCString();
+ }
+
+ if (prop_setter_name && prop_setter_name[0] == '-') {
+ std::optional<const ObjCLanguage::MethodName> prop_setter_method =
+ ObjCLanguage::MethodName::Create(prop_setter_name, true);
+ if (prop_setter_method)
+ prop_setter_name =
+ ConstString(prop_setter_method->GetSelector()).GetCString();
+ }
+
+ // If the names haven't been provided, they need to be filled in.
+ if (!prop_getter_name)
+ prop_getter_name = prop_name;
+ if (!prop_setter_name && prop_name[0] &&
+ !(prop_attributes & DW_APPLE_PROPERTY_readonly)) {
+ StreamString ss;
+
+ ss.Printf("set%c%s:", toupper(prop_name[0]), &prop_name[1]);
+
+ fixed_setter.SetString(ss.GetString());
+ prop_setter_name = fixed_setter.GetCString();
+ }
+}
+
+void DWARFASTParserClang::ParseObjCProperty(
+ const DWARFDIE &die, const DWARFDIE &parent_die,
+ const lldb_private::CompilerType &class_clang_type,
+ DelayedPropertyList &delayed_properties) {
+ // This function can only parse DW_TAG_APPLE_property.
+ assert(die.Tag() == DW_TAG_APPLE_property);
+
+ ModuleSP module_sp = parent_die.GetDWARF()->GetObjectFile()->GetModule();
+
+ const MemberAttributes attrs(die, parent_die, module_sp);
+ const PropertyAttributes propAttrs(die);
+
+ if (!propAttrs.prop_name) {
+ module_sp->ReportError("{0:x8}: DW_TAG_APPLE_property has no name.",
+ die.GetID());
+ return;
+ }
+
+ Type *member_type = die.ResolveTypeUID(attrs.encoding_form.Reference());
+ if (!member_type) {
+ module_sp->ReportError(
+ "{0:x8}: DW_TAG_APPLE_property '{1}' refers to type {2:x16}"
+ " which was unable to be parsed",
+ die.GetID(), propAttrs.prop_name,
+ attrs.encoding_form.Reference().GetOffset());
+ return;
+ }
+
+ ClangASTMetadata metadata;
+ metadata.SetUserID(die.GetID());
+ delayed_properties.push_back(DelayedAddObjCClassProperty(
+ class_clang_type, propAttrs.prop_name,
+ member_type->GetLayoutCompilerType(), propAttrs.prop_setter_name,
+ propAttrs.prop_getter_name, propAttrs.prop_attributes, &metadata));
+}
+
+llvm::Expected<llvm::APInt> DWARFASTParserClang::ExtractIntFromFormValue(
+ const CompilerType &int_type, const DWARFFormValue &form_value) const {
+ clang::QualType qt = ClangUtil::GetQualType(int_type);
+ assert(qt->isIntegralOrEnumerationType());
+ auto ts_ptr = int_type.GetTypeSystem().dyn_cast_or_null<TypeSystemClang>();
+ if (!ts_ptr)
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "TypeSystem not clang");
+ TypeSystemClang &ts = *ts_ptr;
+ clang::ASTContext &ast = ts.getASTContext();
+
+ const unsigned type_bits = ast.getIntWidth(qt);
+ const bool is_unsigned = qt->isUnsignedIntegerType();
+
+ // The maximum int size supported at the moment by this function. Limited
+ // by the uint64_t return type of DWARFFormValue::Signed/Unsigned.
+ constexpr std::size_t max_bit_size = 64;
+
+ // For values bigger than 64 bit (e.g. __int128_t values),
+ // DWARFFormValue's Signed/Unsigned functions will return wrong results so
+ // emit an error for now.
+ if (type_bits > max_bit_size) {
+ auto msg = llvm::formatv("Can only parse integers with up to {0} bits, but "
+ "given integer has {1} bits.",
+ max_bit_size, type_bits);
+ return llvm::createStringError(llvm::inconvertibleErrorCode(), msg.str());
+ }
+
+ // Construct an APInt with the maximum bit size and the given integer.
+ llvm::APInt result(max_bit_size, form_value.Unsigned(), !is_unsigned);
+
+ // Calculate how many bits are required to represent the input value.
+ // For unsigned types, take the number of active bits in the APInt.
+ // For signed types, ask APInt how many bits are required to represent the
+ // signed integer.
+ const unsigned required_bits =
+ is_unsigned ? result.getActiveBits() : result.getSignificantBits();
+
+ // If the input value doesn't fit into the integer type, return an error.
+ if (required_bits > type_bits) {
+ std::string value_as_str = is_unsigned
+ ? std::to_string(form_value.Unsigned())
+ : std::to_string(form_value.Signed());
+ auto msg = llvm::formatv("Can't store {0} value {1} in integer with {2} "
+ "bits.",
+ (is_unsigned ? "unsigned" : "signed"),
+ value_as_str, type_bits);
+ return llvm::createStringError(llvm::inconvertibleErrorCode(), msg.str());
+ }
+
+ // Trim the result to the bit width our the int type.
+ if (result.getBitWidth() > type_bits)
+ result = result.trunc(type_bits);
+ return result;
+}
+
+void DWARFASTParserClang::CreateStaticMemberVariable(
+ const DWARFDIE &die, const MemberAttributes &attrs,
+ const lldb_private::CompilerType &class_clang_type) {
+ Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups);
+ assert(die.Tag() == DW_TAG_member || die.Tag() == DW_TAG_variable);
+
+ Type *var_type = die.ResolveTypeUID(attrs.encoding_form.Reference());
+
+ if (!var_type)
+ return;
+
+ auto accessibility =
+ attrs.accessibility == eAccessNone ? eAccessPublic : attrs.accessibility;
+
+ CompilerType ct = var_type->GetForwardCompilerType();
+ clang::VarDecl *v = TypeSystemClang::AddVariableToRecordType(
+ class_clang_type, attrs.name, ct, accessibility);
+ if (!v) {
+ LLDB_LOG(log, "Failed to add variable to the record type");
+ return;
+ }
+
+ bool unused;
+ // TODO: Support float/double static members as well.
+ if (!ct.IsIntegerOrEnumerationType(unused) || !attrs.const_value_form)
+ return;
+
+ llvm::Expected<llvm::APInt> const_value_or_err =
+ ExtractIntFromFormValue(ct, *attrs.const_value_form);
+ if (!const_value_or_err) {
+ LLDB_LOG_ERROR(log, const_value_or_err.takeError(),
+ "Failed to add const value to variable {1}: {0}",
+ v->getQualifiedNameAsString());
+ return;
+ }
+
+ TypeSystemClang::SetIntegerInitializerForVariable(v, *const_value_or_err);
+}
+
+void DWARFASTParserClang::ParseSingleMember(
+ const DWARFDIE &die, const DWARFDIE &parent_die,
+ const lldb_private::CompilerType &class_clang_type,
+ lldb::AccessType default_accessibility,
+ lldb_private::ClangASTImporter::LayoutInfo &layout_info,
+ FieldInfo &last_field_info) {
+ // This function can only parse DW_TAG_member.
+ assert(die.Tag() == DW_TAG_member);
+
+ ModuleSP module_sp = parent_die.GetDWARF()->GetObjectFile()->GetModule();
+ const dw_tag_t tag = die.Tag();
+ // Get the parent byte size so we can verify any members will fit
+ const uint64_t parent_byte_size =
+ parent_die.GetAttributeValueAsUnsigned(DW_AT_byte_size, UINT64_MAX);
+ const uint64_t parent_bit_size =
+ parent_byte_size == UINT64_MAX ? UINT64_MAX : parent_byte_size * 8;
+
+ const MemberAttributes attrs(die, parent_die, module_sp);
+
+ // Handle static members, which are typically members without
+ // locations. However, GCC doesn't emit DW_AT_data_member_location
+ // for any union members (regardless of linkage).
+ // Non-normative text pre-DWARFv5 recommends marking static
+ // data members with an DW_AT_external flag. Clang emits this consistently
+ // whereas GCC emits it only for static data members if not part of an
+ // anonymous namespace. The flag that is consistently emitted for static
+ // data members is DW_AT_declaration, so we check it instead.
+ // The following block is only necessary to support DWARFv4 and earlier.
+ // Starting with DWARFv5, static data members are marked DW_AT_variable so we
+ // can consistently detect them on both GCC and Clang without below heuristic.
+ if (attrs.member_byte_offset == UINT32_MAX &&
+ attrs.data_bit_offset == UINT64_MAX && attrs.is_declaration) {
+ CreateStaticMemberVariable(die, attrs, class_clang_type);
+ return;
+ }
+
+ Type *member_type = die.ResolveTypeUID(attrs.encoding_form.Reference());
+ if (!member_type) {
+ if (attrs.name)
+ module_sp->ReportError(
+ "{0:x8}: DW_TAG_member '{1}' refers to type {2:x16}"
+ " which was unable to be parsed",
+ die.GetID(), attrs.name, attrs.encoding_form.Reference().GetOffset());
+ else
+ module_sp->ReportError("{0:x8}: DW_TAG_member refers to type {1:x16}"
+ " which was unable to be parsed",
+ die.GetID(),
+ attrs.encoding_form.Reference().GetOffset());
+ return;
+ }
+
+ const uint64_t character_width = 8;
+ const uint64_t word_width = 32;
+ CompilerType member_clang_type = member_type->GetLayoutCompilerType();
+
+ const auto accessibility = attrs.accessibility == eAccessNone
+ ? default_accessibility
+ : attrs.accessibility;
+
+ uint64_t field_bit_offset = (attrs.member_byte_offset == UINT32_MAX
+ ? 0
+ : (attrs.member_byte_offset * 8ULL));
+
+ if (attrs.bit_size > 0) {
+ FieldInfo this_field_info;
+ this_field_info.bit_offset = field_bit_offset;
+ this_field_info.bit_size = attrs.bit_size;
+
+ if (attrs.data_bit_offset != UINT64_MAX) {
+ this_field_info.bit_offset = attrs.data_bit_offset;
+ } else {
+ auto byte_size = attrs.byte_size;
+ if (!byte_size)
+ byte_size = member_type->GetByteSize(nullptr);
+
+ ObjectFile *objfile = die.GetDWARF()->GetObjectFile();
+ if (objfile->GetByteOrder() == eByteOrderLittle) {
+ this_field_info.bit_offset += byte_size.value_or(0) * 8;
+ this_field_info.bit_offset -= (attrs.bit_offset + attrs.bit_size);
+ } else {
+ this_field_info.bit_offset += attrs.bit_offset;
+ }
+ }
+
+ // The ObjC runtime knows the byte offset but we still need to provide
+ // the bit-offset in the layout. It just means something different then
+ // what it does in C and C++. So we skip this check for ObjC types.
+ //
+ // We also skip this for fields of a union since they will all have a
+ // zero offset.
+ if (!TypeSystemClang::IsObjCObjectOrInterfaceType(class_clang_type) &&
+ !(parent_die.Tag() == DW_TAG_union_type &&
+ this_field_info.bit_offset == 0) &&
+ ((this_field_info.bit_offset >= parent_bit_size) ||
+ (last_field_info.IsBitfield() &&
+ !last_field_info.NextBitfieldOffsetIsValid(
+ this_field_info.bit_offset)))) {
+ ObjectFile *objfile = die.GetDWARF()->GetObjectFile();
+ objfile->GetModule()->ReportWarning(
+ "{0:x16}: {1} ({2}) bitfield named \"{3}\" has invalid "
+ "bit offset ({4:x8}) member will be ignored. Please file a bug "
+ "against the "
+ "compiler and include the preprocessed output for {5}\n",
+ die.GetID(), DW_TAG_value_to_name(tag), tag, attrs.name,
+ this_field_info.bit_offset, GetUnitName(parent_die).c_str());
+ return;
+ }
+
+ // Update the field bit offset we will report for layout
+ field_bit_offset = this_field_info.bit_offset;
+
+ // Objective-C has invalid DW_AT_bit_offset values in older
+ // versions of clang, so we have to be careful and only insert
+ // unnamed bitfields if we have a new enough clang.
+ bool detect_unnamed_bitfields = true;
+
+ if (TypeSystemClang::IsObjCObjectOrInterfaceType(class_clang_type))
+ detect_unnamed_bitfields =
+ die.GetCU()->Supports_unnamed_objc_bitfields();
+
+ if (detect_unnamed_bitfields) {
+ std::optional<FieldInfo> unnamed_field_info;
+ uint64_t last_field_end =
+ last_field_info.bit_offset + last_field_info.bit_size;
+
+ if (!last_field_info.IsBitfield()) {
+ // The last field was not a bit-field...
+ // but if it did take up the entire word then we need to extend
+ // last_field_end so the bit-field does not step into the last
+ // fields padding.
+ if (last_field_end != 0 && ((last_field_end % word_width) != 0))
+ last_field_end += word_width - (last_field_end % word_width);
+ }
+
+ if (ShouldCreateUnnamedBitfield(last_field_info, last_field_end,
+ this_field_info, layout_info)) {
+ unnamed_field_info = FieldInfo{};
+ unnamed_field_info->bit_size =
+ this_field_info.bit_offset - last_field_end;
+ unnamed_field_info->bit_offset = last_field_end;
+ }
+
+ if (unnamed_field_info) {
+ clang::FieldDecl *unnamed_bitfield_decl =
+ TypeSystemClang::AddFieldToRecordType(
+ class_clang_type, llvm::StringRef(),
+ m_ast.GetBuiltinTypeForEncodingAndBitSize(eEncodingSint,
+ word_width),
+ accessibility, unnamed_field_info->bit_size);
+
+ layout_info.field_offsets.insert(std::make_pair(
+ unnamed_bitfield_decl, unnamed_field_info->bit_offset));
+ }
+ }
+
+ last_field_info = this_field_info;
+ last_field_info.SetIsBitfield(true);
+ } else {
+ last_field_info.bit_offset = field_bit_offset;
+
+ if (std::optional<uint64_t> clang_type_size =
+ member_type->GetByteSize(nullptr)) {
+ last_field_info.bit_size = *clang_type_size * character_width;
+ }
+
+ last_field_info.SetIsBitfield(false);
+ }
+
+ // Don't turn artificial members such as vtable pointers into real FieldDecls
+ // in our AST. Clang will re-create those articial members and they would
+ // otherwise just overlap in the layout with the FieldDecls we add here.
+ // This needs to be done after updating FieldInfo which keeps track of where
+ // field start/end so we don't later try to fill the space of this
+ // artificial member with (unnamed bitfield) padding.
+ if (attrs.is_artificial && ShouldIgnoreArtificialField(attrs.name)) {
+ last_field_info.SetIsArtificial(true);
+ return;
+ }
+
+ if (!member_clang_type.IsCompleteType())
+ member_clang_type.GetCompleteType();
+
+ {
+ // Older versions of clang emit the same DWARF for array[0] and array[1]. If
+ // the current field is at the end of the structure, then there is
+ // definitely no room for extra elements and we override the type to
+ // array[0]. This was fixed by f454dfb6b5af.
+ CompilerType member_array_element_type;
+ uint64_t member_array_size;
+ bool member_array_is_incomplete;
+
+ if (member_clang_type.IsArrayType(&member_array_element_type,
+ &member_array_size,
+ &member_array_is_incomplete) &&
+ !member_array_is_incomplete) {
+ uint64_t parent_byte_size =
+ parent_die.GetAttributeValueAsUnsigned(DW_AT_byte_size, UINT64_MAX);
+
+ if (attrs.member_byte_offset >= parent_byte_size) {
+ if (member_array_size != 1 &&
+ (member_array_size != 0 ||
+ attrs.member_byte_offset > parent_byte_size)) {
+ module_sp->ReportError(
+ "{0:x8}: DW_TAG_member '{1}' refers to type {2:x16}"
+ " which extends beyond the bounds of {3:x8}",
+ die.GetID(), attrs.name,
+ attrs.encoding_form.Reference().GetOffset(), parent_die.GetID());
+ }
+
+ member_clang_type =
+ m_ast.CreateArrayType(member_array_element_type, 0, false);
+ }
+ }
+ }
+
+ TypeSystemClang::RequireCompleteType(member_clang_type);
+
+ clang::FieldDecl *field_decl = TypeSystemClang::AddFieldToRecordType(
+ class_clang_type, attrs.name, member_clang_type, accessibility,
+ attrs.bit_size);
+
+ m_ast.SetMetadataAsUserID(field_decl, die.GetID());
+
+ layout_info.field_offsets.insert(
+ std::make_pair(field_decl, field_bit_offset));
+}
+
+bool DWARFASTParserClang::ParseChildMembers(
+ const DWARFDIE &parent_die, CompilerType &class_clang_type,
+ std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> &base_classes,
+ std::vector<DWARFDIE> &member_function_dies,
+ std::vector<DWARFDIE> &contained_type_dies,
+ DelayedPropertyList &delayed_properties,
+ const AccessType default_accessibility,
+ ClangASTImporter::LayoutInfo &layout_info) {
+ if (!parent_die)
+ return false;
+
+ FieldInfo last_field_info;
+
+ ModuleSP module_sp = parent_die.GetDWARF()->GetObjectFile()->GetModule();
+ auto ts = class_clang_type.GetTypeSystem();
+ auto ast = ts.dyn_cast_or_null<TypeSystemClang>();
+ if (ast == nullptr)
+ return false;
+
+ for (DWARFDIE die : parent_die.children()) {
+ dw_tag_t tag = die.Tag();
+
+ switch (tag) {
+ case DW_TAG_APPLE_property:
+ ParseObjCProperty(die, parent_die, class_clang_type, delayed_properties);
+ break;
+
+ case DW_TAG_variant_part:
+ if (die.GetCU()->GetDWARFLanguageType() == eLanguageTypeRust) {
+ ParseRustVariantPart(die, parent_die, class_clang_type,
+ default_accessibility, layout_info);
+ }
+ break;
+
+ case DW_TAG_variable: {
+ const MemberAttributes attrs(die, parent_die, module_sp);
+ CreateStaticMemberVariable(die, attrs, class_clang_type);
+ } break;
+ case DW_TAG_member:
+ ParseSingleMember(die, parent_die, class_clang_type,
+ default_accessibility, layout_info, last_field_info);
+ break;
+
+ case DW_TAG_subprogram:
+ // Let the type parsing code handle this one for us.
+ member_function_dies.push_back(die);
+ break;
+
+ case DW_TAG_inheritance:
+ ParseInheritance(die, parent_die, class_clang_type, default_accessibility,
+ module_sp, base_classes, layout_info);
+ break;
+
+ default:
+ if (llvm::dwarf::isType(tag))
+ contained_type_dies.push_back(die);
+ break;
+ }
+ }
+
+ return true;
+}
+
+size_t DWARFASTParserClang::ParseChildParameters(
+ clang::DeclContext *containing_decl_ctx, const DWARFDIE &parent_die,
+ bool skip_artificial, bool &is_static, bool &is_variadic,
+ bool &has_template_params, std::vector<CompilerType> &function_param_types,
+ std::vector<clang::ParmVarDecl *> &function_param_decls,
+ unsigned &type_quals) {
+ if (!parent_die)
+ return 0;
+
+ size_t arg_idx = 0;
+ for (DWARFDIE die : parent_die.children()) {
+ const dw_tag_t tag = die.Tag();
+ switch (tag) {
+ case DW_TAG_formal_parameter: {
+ DWARFAttributes attributes = die.GetAttributes();
+ if (attributes.Size() == 0) {
+ arg_idx++;
+ break;
+ }
+
+ const char *name = nullptr;
+ DWARFFormValue param_type_die_form;
+ bool is_artificial = false;
+ // one of None, Auto, Register, Extern, Static, PrivateExtern
+
+ clang::StorageClass storage = clang::SC_None;
+ uint32_t i;
+ for (i = 0; i < attributes.Size(); ++i) {
+ const dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(i, form_value)) {
+ switch (attr) {
+ case DW_AT_name:
+ name = form_value.AsCString();
+ break;
+ case DW_AT_type:
+ param_type_die_form = form_value;
+ break;
+ case DW_AT_artificial:
+ is_artificial = form_value.Boolean();
+ break;
+ case DW_AT_location:
+ case DW_AT_const_value:
+ case DW_AT_default_value:
+ case DW_AT_description:
+ case DW_AT_endianity:
+ case DW_AT_is_optional:
+ case DW_AT_segment:
+ case DW_AT_variable_parameter:
+ default:
+ case DW_AT_abstract_origin:
+ case DW_AT_sibling:
+ break;
+ }
+ }
+ }
+
+ bool skip = false;
+ if (skip_artificial && is_artificial) {
+ // In order to determine if a C++ member function is "const" we
+ // have to look at the const-ness of "this"...
+ if (arg_idx == 0 &&
+ DeclKindIsCXXClass(containing_decl_ctx->getDeclKind()) &&
+ // Often times compilers omit the "this" name for the
+ // specification DIEs, so we can't rely upon the name being in
+ // the formal parameter DIE...
+ (name == nullptr || ::strcmp(name, "this") == 0)) {
+ Type *this_type = die.ResolveTypeUID(param_type_die_form.Reference());
+ if (this_type) {
+ uint32_t encoding_mask = this_type->GetEncodingMask();
+ if (encoding_mask & Type::eEncodingIsPointerUID) {
+ is_static = false;
+
+ if (encoding_mask & (1u << Type::eEncodingIsConstUID))
+ type_quals |= clang::Qualifiers::Const;
+ if (encoding_mask & (1u << Type::eEncodingIsVolatileUID))
+ type_quals |= clang::Qualifiers::Volatile;
+ }
+ }
+ }
+ skip = true;
+ }
+
+ if (!skip) {
+ Type *type = die.ResolveTypeUID(param_type_die_form.Reference());
+ if (type) {
+ function_param_types.push_back(type->GetForwardCompilerType());
+
+ clang::ParmVarDecl *param_var_decl = m_ast.CreateParameterDeclaration(
+ containing_decl_ctx, GetOwningClangModule(die), name,
+ type->GetForwardCompilerType(), storage);
+ assert(param_var_decl);
+ function_param_decls.push_back(param_var_decl);
+
+ m_ast.SetMetadataAsUserID(param_var_decl, die.GetID());
+ }
+ }
+ arg_idx++;
+ } break;
+
+ case DW_TAG_unspecified_parameters:
+ is_variadic = true;
+ break;
+
+ case DW_TAG_template_type_parameter:
+ case DW_TAG_template_value_parameter:
+ case DW_TAG_GNU_template_parameter_pack:
+ // The one caller of this was never using the template_param_infos, and
+ // the local variable was taking up a large amount of stack space in
+ // SymbolFileDWARF::ParseType() so this was removed. If we ever need the
+ // template params back, we can add them back.
+ // ParseTemplateDIE (dwarf_cu, die, template_param_infos);
+ has_template_params = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ return arg_idx;
+}
+
+clang::Decl *DWARFASTParserClang::GetClangDeclForDIE(const DWARFDIE &die) {
+ if (!die)
+ return nullptr;
+
+ switch (die.Tag()) {
+ case DW_TAG_constant:
+ case DW_TAG_formal_parameter:
+ case DW_TAG_imported_declaration:
+ case DW_TAG_imported_module:
+ break;
+ case DW_TAG_variable:
+ // This means 'die' is a C++ static data member.
+ // We don't want to create decls for such members
+ // here.
+ if (auto parent = die.GetParent();
+ parent.IsValid() && TagIsRecordType(parent.Tag()))
+ return nullptr;
+ break;
+ default:
+ return nullptr;
+ }
+
+ DIEToDeclMap::iterator cache_pos = m_die_to_decl.find(die.GetDIE());
+ if (cache_pos != m_die_to_decl.end())
+ return cache_pos->second;
+
+ if (DWARFDIE spec_die = die.GetReferencedDIE(DW_AT_specification)) {
+ clang::Decl *decl = GetClangDeclForDIE(spec_die);
+ m_die_to_decl[die.GetDIE()] = decl;
+ return decl;
+ }
+
+ if (DWARFDIE abstract_origin_die =
+ die.GetReferencedDIE(DW_AT_abstract_origin)) {
+ clang::Decl *decl = GetClangDeclForDIE(abstract_origin_die);
+ m_die_to_decl[die.GetDIE()] = decl;
+ return decl;
+ }
+
+ clang::Decl *decl = nullptr;
+ switch (die.Tag()) {
+ case DW_TAG_variable:
+ case DW_TAG_constant:
+ case DW_TAG_formal_parameter: {
+ SymbolFileDWARF *dwarf = die.GetDWARF();
+ Type *type = GetTypeForDIE(die);
+ if (dwarf && type) {
+ const char *name = die.GetName();
+ clang::DeclContext *decl_context =
+ TypeSystemClang::DeclContextGetAsDeclContext(
+ dwarf->GetDeclContextContainingUID(die.GetID()));
+ decl = m_ast.CreateVariableDeclaration(
+ decl_context, GetOwningClangModule(die), name,
+ ClangUtil::GetQualType(type->GetForwardCompilerType()));
+ }
+ break;
+ }
+ case DW_TAG_imported_declaration: {
+ SymbolFileDWARF *dwarf = die.GetDWARF();
+ DWARFDIE imported_uid = die.GetAttributeValueAsReferenceDIE(DW_AT_import);
+ if (imported_uid) {
+ CompilerDecl imported_decl = SymbolFileDWARF::GetDecl(imported_uid);
+ if (imported_decl) {
+ clang::DeclContext *decl_context =
+ TypeSystemClang::DeclContextGetAsDeclContext(
+ dwarf->GetDeclContextContainingUID(die.GetID()));
+ if (clang::NamedDecl *clang_imported_decl =
+ llvm::dyn_cast<clang::NamedDecl>(
+ (clang::Decl *)imported_decl.GetOpaqueDecl()))
+ decl = m_ast.CreateUsingDeclaration(
+ decl_context, OptionalClangModuleID(), clang_imported_decl);
+ }
+ }
+ break;
+ }
+ case DW_TAG_imported_module: {
+ SymbolFileDWARF *dwarf = die.GetDWARF();
+ DWARFDIE imported_uid = die.GetAttributeValueAsReferenceDIE(DW_AT_import);
+
+ if (imported_uid) {
+ CompilerDeclContext imported_decl_ctx =
+ SymbolFileDWARF::GetDeclContext(imported_uid);
+ if (imported_decl_ctx) {
+ clang::DeclContext *decl_context =
+ TypeSystemClang::DeclContextGetAsDeclContext(
+ dwarf->GetDeclContextContainingUID(die.GetID()));
+ if (clang::NamespaceDecl *ns_decl =
+ TypeSystemClang::DeclContextGetAsNamespaceDecl(
+ imported_decl_ctx))
+ decl = m_ast.CreateUsingDirectiveDeclaration(
+ decl_context, OptionalClangModuleID(), ns_decl);
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ m_die_to_decl[die.GetDIE()] = decl;
+
+ return decl;
+}
+
+clang::DeclContext *
+DWARFASTParserClang::GetClangDeclContextForDIE(const DWARFDIE &die) {
+ if (die) {
+ clang::DeclContext *decl_ctx = GetCachedClangDeclContextForDIE(die);
+ if (decl_ctx)
+ return decl_ctx;
+
+ bool try_parsing_type = true;
+ switch (die.Tag()) {
+ case DW_TAG_compile_unit:
+ case DW_TAG_partial_unit:
+ decl_ctx = m_ast.GetTranslationUnitDecl();
+ try_parsing_type = false;
+ break;
+
+ case DW_TAG_namespace:
+ decl_ctx = ResolveNamespaceDIE(die);
+ try_parsing_type = false;
+ break;
+
+ case DW_TAG_imported_declaration:
+ decl_ctx = ResolveImportedDeclarationDIE(die);
+ try_parsing_type = false;
+ break;
+
+ case DW_TAG_lexical_block:
+ decl_ctx = GetDeclContextForBlock(die);
+ try_parsing_type = false;
+ break;
+
+ default:
+ break;
+ }
+
+ if (decl_ctx == nullptr && try_parsing_type) {
+ Type *type = die.GetDWARF()->ResolveType(die);
+ if (type)
+ decl_ctx = GetCachedClangDeclContextForDIE(die);
+ }
+
+ if (decl_ctx) {
+ LinkDeclContextToDIE(decl_ctx, die);
+ return decl_ctx;
+ }
+ }
+ return nullptr;
+}
+
+OptionalClangModuleID
+DWARFASTParserClang::GetOwningClangModule(const DWARFDIE &die) {
+ if (!die.IsValid())
+ return {};
+
+ for (DWARFDIE parent = die.GetParent(); parent.IsValid();
+ parent = parent.GetParent()) {
+ const dw_tag_t tag = parent.Tag();
+ if (tag == DW_TAG_module) {
+ DWARFDIE module_die = parent;
+ auto it = m_die_to_module.find(module_die.GetDIE());
+ if (it != m_die_to_module.end())
+ return it->second;
+ const char *name =
+ module_die.GetAttributeValueAsString(DW_AT_name, nullptr);
+ if (!name)
+ return {};
+
+ OptionalClangModuleID id =
+ m_ast.GetOrCreateClangModule(name, GetOwningClangModule(module_die));
+ m_die_to_module.insert({module_die.GetDIE(), id});
+ return id;
+ }
+ }
+ return {};
+}
+
+static bool IsSubroutine(const DWARFDIE &die) {
+ switch (die.Tag()) {
+ case DW_TAG_subprogram:
+ case DW_TAG_inlined_subroutine:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static DWARFDIE GetContainingFunctionWithAbstractOrigin(const DWARFDIE &die) {
+ for (DWARFDIE candidate = die; candidate; candidate = candidate.GetParent()) {
+ if (IsSubroutine(candidate)) {
+ if (candidate.GetReferencedDIE(DW_AT_abstract_origin)) {
+ return candidate;
+ } else {
+ return DWARFDIE();
+ }
+ }
+ }
+ assert(0 && "Shouldn't call GetContainingFunctionWithAbstractOrigin on "
+ "something not in a function");
+ return DWARFDIE();
+}
+
+static DWARFDIE FindAnyChildWithAbstractOrigin(const DWARFDIE &context) {
+ for (DWARFDIE candidate : context.children()) {
+ if (candidate.GetReferencedDIE(DW_AT_abstract_origin)) {
+ return candidate;
+ }
+ }
+ return DWARFDIE();
+}
+
+static DWARFDIE FindFirstChildWithAbstractOrigin(const DWARFDIE &block,
+ const DWARFDIE &function) {
+ assert(IsSubroutine(function));
+ for (DWARFDIE context = block; context != function.GetParent();
+ context = context.GetParent()) {
+ assert(!IsSubroutine(context) || context == function);
+ if (DWARFDIE child = FindAnyChildWithAbstractOrigin(context)) {
+ return child;
+ }
+ }
+ return DWARFDIE();
+}
+
+clang::DeclContext *
+DWARFASTParserClang::GetDeclContextForBlock(const DWARFDIE &die) {
+ assert(die.Tag() == DW_TAG_lexical_block);
+ DWARFDIE containing_function_with_abstract_origin =
+ GetContainingFunctionWithAbstractOrigin(die);
+ if (!containing_function_with_abstract_origin) {
+ return (clang::DeclContext *)ResolveBlockDIE(die);
+ }
+ DWARFDIE child = FindFirstChildWithAbstractOrigin(
+ die, containing_function_with_abstract_origin);
+ CompilerDeclContext decl_context =
+ GetDeclContextContainingUIDFromDWARF(child);
+ return (clang::DeclContext *)decl_context.GetOpaqueDeclContext();
+}
+
+clang::BlockDecl *DWARFASTParserClang::ResolveBlockDIE(const DWARFDIE &die) {
+ if (die && die.Tag() == DW_TAG_lexical_block) {
+ clang::BlockDecl *decl =
+ llvm::cast_or_null<clang::BlockDecl>(m_die_to_decl_ctx[die.GetDIE()]);
+
+ if (!decl) {
+ DWARFDIE decl_context_die;
+ clang::DeclContext *decl_context =
+ GetClangDeclContextContainingDIE(die, &decl_context_die);
+ decl =
+ m_ast.CreateBlockDeclaration(decl_context, GetOwningClangModule(die));
+
+ if (decl)
+ LinkDeclContextToDIE((clang::DeclContext *)decl, die);
+ }
+
+ return decl;
+ }
+ return nullptr;
+}
+
+clang::NamespaceDecl *
+DWARFASTParserClang::ResolveNamespaceDIE(const DWARFDIE &die) {
+ if (die && die.Tag() == DW_TAG_namespace) {
+ // See if we already parsed this namespace DIE and associated it with a
+ // uniqued namespace declaration
+ clang::NamespaceDecl *namespace_decl =
+ static_cast<clang::NamespaceDecl *>(m_die_to_decl_ctx[die.GetDIE()]);
+ if (namespace_decl)
+ return namespace_decl;
+ else {
+ const char *namespace_name = die.GetName();
+ clang::DeclContext *containing_decl_ctx =
+ GetClangDeclContextContainingDIE(die, nullptr);
+ bool is_inline =
+ die.GetAttributeValueAsUnsigned(DW_AT_export_symbols, 0) != 0;
+
+ namespace_decl = m_ast.GetUniqueNamespaceDeclaration(
+ namespace_name, containing_decl_ctx, GetOwningClangModule(die),
+ is_inline);
+
+ if (namespace_decl)
+ LinkDeclContextToDIE((clang::DeclContext *)namespace_decl, die);
+ return namespace_decl;
+ }
+ }
+ return nullptr;
+}
+
+clang::NamespaceDecl *
+DWARFASTParserClang::ResolveImportedDeclarationDIE(const DWARFDIE &die) {
+ assert(die && die.Tag() == DW_TAG_imported_declaration);
+
+ // See if we cached a NamespaceDecl for this imported declaration
+ // already
+ auto it = m_die_to_decl_ctx.find(die.GetDIE());
+ if (it != m_die_to_decl_ctx.end())
+ return static_cast<clang::NamespaceDecl *>(it->getSecond());
+
+ clang::NamespaceDecl *namespace_decl = nullptr;
+
+ const DWARFDIE imported_uid =
+ die.GetAttributeValueAsReferenceDIE(DW_AT_import);
+ if (!imported_uid)
+ return nullptr;
+
+ switch (imported_uid.Tag()) {
+ case DW_TAG_imported_declaration:
+ namespace_decl = ResolveImportedDeclarationDIE(imported_uid);
+ break;
+ case DW_TAG_namespace:
+ namespace_decl = ResolveNamespaceDIE(imported_uid);
+ break;
+ default:
+ return nullptr;
+ }
+
+ if (!namespace_decl)
+ return nullptr;
+
+ LinkDeclContextToDIE(namespace_decl, die);
+
+ return namespace_decl;
+}
+
+clang::DeclContext *DWARFASTParserClang::GetClangDeclContextContainingDIE(
+ const DWARFDIE &die, DWARFDIE *decl_ctx_die_copy) {
+ SymbolFileDWARF *dwarf = die.GetDWARF();
+
+ DWARFDIE decl_ctx_die = dwarf->GetDeclContextDIEContainingDIE(die);
+
+ if (decl_ctx_die_copy)
+ *decl_ctx_die_copy = decl_ctx_die;
+
+ if (decl_ctx_die) {
+ clang::DeclContext *clang_decl_ctx =
+ GetClangDeclContextForDIE(decl_ctx_die);
+ if (clang_decl_ctx)
+ return clang_decl_ctx;
+ }
+ return m_ast.GetTranslationUnitDecl();
+}
+
+clang::DeclContext *
+DWARFASTParserClang::GetCachedClangDeclContextForDIE(const DWARFDIE &die) {
+ if (die) {
+ DIEToDeclContextMap::iterator pos = m_die_to_decl_ctx.find(die.GetDIE());
+ if (pos != m_die_to_decl_ctx.end())
+ return pos->second;
+ }
+ return nullptr;
+}
+
+void DWARFASTParserClang::LinkDeclContextToDIE(clang::DeclContext *decl_ctx,
+ const DWARFDIE &die) {
+ m_die_to_decl_ctx[die.GetDIE()] = decl_ctx;
+ // There can be many DIEs for a single decl context
+ // m_decl_ctx_to_die[decl_ctx].insert(die.GetDIE());
+ m_decl_ctx_to_die.insert(std::make_pair(decl_ctx, die));
+}
+
+bool DWARFASTParserClang::CopyUniqueClassMethodTypes(
+ const DWARFDIE &src_class_die, const DWARFDIE &dst_class_die,
+ lldb_private::Type *class_type, std::vector<DWARFDIE> &failures) {
+ if (!class_type || !src_class_die || !dst_class_die)
+ return false;
+ if (src_class_die.Tag() != dst_class_die.Tag())
+ return false;
+
+ // We need to complete the class type so we can get all of the method types
+ // parsed so we can then unique those types to their equivalent counterparts
+ // in "dst_cu" and "dst_class_die"
+ class_type->GetFullCompilerType();
+
+ auto gather = [](DWARFDIE die, UniqueCStringMap<DWARFDIE> &map,
+ UniqueCStringMap<DWARFDIE> &map_artificial) {
+ if (die.Tag() != DW_TAG_subprogram)
+ return;
+ // Make sure this is a declaration and not a concrete instance by looking
+ // for DW_AT_declaration set to 1. Sometimes concrete function instances are
+ // placed inside the class definitions and shouldn't be included in the list
+ // of things that are tracking here.
+ if (die.GetAttributeValueAsUnsigned(DW_AT_declaration, 0) != 1)
+ return;
+
+ if (const char *name = die.GetMangledName()) {
+ ConstString const_name(name);
+ if (die.GetAttributeValueAsUnsigned(DW_AT_artificial, 0))
+ map_artificial.Append(const_name, die);
+ else
+ map.Append(const_name, die);
+ }
+ };
+
+ UniqueCStringMap<DWARFDIE> src_name_to_die;
+ UniqueCStringMap<DWARFDIE> dst_name_to_die;
+ UniqueCStringMap<DWARFDIE> src_name_to_die_artificial;
+ UniqueCStringMap<DWARFDIE> dst_name_to_die_artificial;
+ for (DWARFDIE src_die = src_class_die.GetFirstChild(); src_die.IsValid();
+ src_die = src_die.GetSibling()) {
+ gather(src_die, src_name_to_die, src_name_to_die_artificial);
+ }
+ for (DWARFDIE dst_die = dst_class_die.GetFirstChild(); dst_die.IsValid();
+ dst_die = dst_die.GetSibling()) {
+ gather(dst_die, dst_name_to_die, dst_name_to_die_artificial);
+ }
+ const uint32_t src_size = src_name_to_die.GetSize();
+ const uint32_t dst_size = dst_name_to_die.GetSize();
+
+ // Is everything kosher so we can go through the members at top speed?
+ bool fast_path = true;
+
+ if (src_size != dst_size)
+ fast_path = false;
+
+ uint32_t idx;
+
+ if (fast_path) {
+ for (idx = 0; idx < src_size; ++idx) {
+ DWARFDIE src_die = src_name_to_die.GetValueAtIndexUnchecked(idx);
+ DWARFDIE dst_die = dst_name_to_die.GetValueAtIndexUnchecked(idx);
+
+ if (src_die.Tag() != dst_die.Tag())
+ fast_path = false;
+
+ const char *src_name = src_die.GetMangledName();
+ const char *dst_name = dst_die.GetMangledName();
+
+ // Make sure the names match
+ if (src_name == dst_name || (strcmp(src_name, dst_name) == 0))
+ continue;
+
+ fast_path = false;
+ }
+ }
+
+ DWARFASTParserClang *src_dwarf_ast_parser =
+ static_cast<DWARFASTParserClang *>(
+ SymbolFileDWARF::GetDWARFParser(*src_class_die.GetCU()));
+ DWARFASTParserClang *dst_dwarf_ast_parser =
+ static_cast<DWARFASTParserClang *>(
+ SymbolFileDWARF::GetDWARFParser(*dst_class_die.GetCU()));
+ auto link = [&](DWARFDIE src, DWARFDIE dst) {
+ SymbolFileDWARF::DIEToTypePtr &die_to_type =
+ dst_class_die.GetDWARF()->GetDIEToType();
+ clang::DeclContext *dst_decl_ctx =
+ dst_dwarf_ast_parser->m_die_to_decl_ctx[dst.GetDIE()];
+ if (dst_decl_ctx)
+ src_dwarf_ast_parser->LinkDeclContextToDIE(dst_decl_ctx, src);
+
+ if (Type *src_child_type = die_to_type.lookup(src.GetDIE()))
+ die_to_type[dst.GetDIE()] = src_child_type;
+ };
+
+ // Now do the work of linking the DeclContexts and Types.
+ if (fast_path) {
+ // We can do this quickly. Just run across the tables index-for-index
+ // since we know each node has matching names and tags.
+ for (idx = 0; idx < src_size; ++idx) {
+ link(src_name_to_die.GetValueAtIndexUnchecked(idx),
+ dst_name_to_die.GetValueAtIndexUnchecked(idx));
+ }
+ } else {
+ // We must do this slowly. For each member of the destination, look up a
+ // member in the source with the same name, check its tag, and unique them
+ // if everything matches up. Report failures.
+
+ if (!src_name_to_die.IsEmpty() && !dst_name_to_die.IsEmpty()) {
+ src_name_to_die.Sort();
+
+ for (idx = 0; idx < dst_size; ++idx) {
+ ConstString dst_name = dst_name_to_die.GetCStringAtIndex(idx);
+ DWARFDIE dst_die = dst_name_to_die.GetValueAtIndexUnchecked(idx);
+ DWARFDIE src_die = src_name_to_die.Find(dst_name, DWARFDIE());
+
+ if (src_die && (src_die.Tag() == dst_die.Tag()))
+ link(src_die, dst_die);
+ else
+ failures.push_back(dst_die);
+ }
+ }
+ }
+
+ const uint32_t src_size_artificial = src_name_to_die_artificial.GetSize();
+ const uint32_t dst_size_artificial = dst_name_to_die_artificial.GetSize();
+
+ if (src_size_artificial && dst_size_artificial) {
+ dst_name_to_die_artificial.Sort();
+
+ for (idx = 0; idx < src_size_artificial; ++idx) {
+ ConstString src_name_artificial =
+ src_name_to_die_artificial.GetCStringAtIndex(idx);
+ DWARFDIE src_die =
+ src_name_to_die_artificial.GetValueAtIndexUnchecked(idx);
+ DWARFDIE dst_die =
+ dst_name_to_die_artificial.Find(src_name_artificial, DWARFDIE());
+
+ // Both classes have the artificial types, link them
+ if (dst_die)
+ link(src_die, dst_die);
+ }
+ }
+
+ if (dst_size_artificial) {
+ for (idx = 0; idx < dst_size_artificial; ++idx) {
+ failures.push_back(
+ dst_name_to_die_artificial.GetValueAtIndexUnchecked(idx));
+ }
+ }
+
+ return !failures.empty();
+}
+
+bool DWARFASTParserClang::ShouldCreateUnnamedBitfield(
+ FieldInfo const &last_field_info, uint64_t last_field_end,
+ FieldInfo const &this_field_info,
+ lldb_private::ClangASTImporter::LayoutInfo const &layout_info) const {
+ // If we have a gap between the last_field_end and the current
+ // field we have an unnamed bit-field.
+ if (this_field_info.bit_offset <= last_field_end)
+ return false;
+
+ // If we have a base class, we assume there is no unnamed
+ // bit-field if either of the following is true:
+ // (a) this is the first field since the gap can be
+ // attributed to the members from the base class.
+ // FIXME: This assumption is not correct if the first field of
+ // the derived class is indeed an unnamed bit-field. We currently
+ // do not have the machinary to track the offset of the last field
+ // of classes we have seen before, so we are not handling this case.
+ // (b) Or, the first member of the derived class was a vtable pointer.
+ // In this case we don't want to create an unnamed bitfield either
+ // since those will be inserted by clang later.
+ const bool have_base = layout_info.base_offsets.size() != 0;
+ const bool this_is_first_field =
+ last_field_info.bit_offset == 0 && last_field_info.bit_size == 0;
+ const bool first_field_is_vptr =
+ last_field_info.bit_offset == 0 && last_field_info.IsArtificial();
+
+ if (have_base && (this_is_first_field || first_field_is_vptr))
+ return false;
+
+ return true;
+}
+
+void DWARFASTParserClang::ParseRustVariantPart(
+ DWARFDIE &die, const DWARFDIE &parent_die, CompilerType &class_clang_type,
+ const lldb::AccessType default_accesibility,
+ ClangASTImporter::LayoutInfo &layout_info) {
+ assert(die.Tag() == llvm::dwarf::DW_TAG_variant_part);
+ assert(SymbolFileDWARF::GetLanguage(*die.GetCU()) ==
+ LanguageType::eLanguageTypeRust);
+
+ ModuleSP module_sp = parent_die.GetDWARF()->GetObjectFile()->GetModule();
+
+ VariantPart variants(die, parent_die, module_sp);
+
+ auto discriminant_type =
+ die.ResolveTypeUID(variants.discriminant().type_ref.Reference());
+
+ auto decl_context = m_ast.GetDeclContextForType(class_clang_type);
+
+ auto inner_holder = m_ast.CreateRecordType(
+ decl_context, OptionalClangModuleID(), lldb::eAccessPublic,
+ std::string(
+ llvm::formatv("{0}$Inner", class_clang_type.GetTypeName(false))),
+ llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeRust);
+ m_ast.StartTagDeclarationDefinition(inner_holder);
+ m_ast.SetIsPacked(inner_holder);
+
+ for (auto member : variants.members()) {
+
+ auto has_discriminant = !member.IsDefault();
+
+ auto member_type = die.ResolveTypeUID(member.type_ref.Reference());
+
+ auto field_type = m_ast.CreateRecordType(
+ m_ast.GetDeclContextForType(inner_holder), OptionalClangModuleID(),
+ lldb::eAccessPublic,
+ std::string(llvm::formatv("{0}$Variant", member.GetName())),
+ llvm::to_underlying(clang::TagTypeKind::Struct),
+ lldb::eLanguageTypeRust);
+
+ m_ast.StartTagDeclarationDefinition(field_type);
+ auto offset = member.byte_offset;
+
+ if (has_discriminant) {
+ m_ast.AddFieldToRecordType(
+ field_type, "$discr$", discriminant_type->GetFullCompilerType(),
+ lldb::eAccessPublic, variants.discriminant().byte_offset);
+ offset += discriminant_type->GetByteSize(nullptr).value_or(0);
+ }
+
+ m_ast.AddFieldToRecordType(field_type, "value",
+ member_type->GetFullCompilerType(),
+ lldb::eAccessPublic, offset * 8);
+
+ m_ast.CompleteTagDeclarationDefinition(field_type);
+
+ auto name = has_discriminant
+ ? llvm::formatv("$variant${0}", member.discr_value.value())
+ : std::string("$variant$");
+
+ auto variant_decl =
+ m_ast.AddFieldToRecordType(inner_holder, llvm::StringRef(name),
+ field_type, default_accesibility, 0);
+
+ layout_info.field_offsets.insert({variant_decl, 0});
+ }
+
+ auto inner_field = m_ast.AddFieldToRecordType(class_clang_type,
+ llvm::StringRef("$variants$"),
+ inner_holder, eAccessPublic, 0);
+
+ m_ast.CompleteTagDeclarationDefinition(inner_holder);
+
+ layout_info.field_offsets.insert({inner_field, 0});
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
new file mode 100644
index 000000000000..4b0ae026bce7
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
@@ -0,0 +1,516 @@
+//===-- DWARFASTParserClang.h -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFASTPARSERCLANG_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFASTPARSERCLANG_H
+
+#include "clang/AST/CharUnits.h"
+#include "clang/AST/Type.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallVector.h"
+
+#include "DWARFASTParser.h"
+#include "DWARFDIE.h"
+#include "DWARFDefines.h"
+#include "DWARFFormValue.h"
+#include "LogChannelDWARF.h"
+#include "lldb/Core/PluginInterface.h"
+
+#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
+#include "Plugins/Language/ObjC/ObjCLanguage.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+
+#include <optional>
+#include <vector>
+
+namespace lldb_private {
+class CompileUnit;
+}
+namespace lldb_private::plugin {
+namespace dwarf {
+class DWARFDebugInfoEntry;
+class SymbolFileDWARF;
+} // namespace dwarf
+} // namespace lldb_private::plugin
+
+struct ParsedDWARFTypeAttributes;
+
+class DWARFASTParserClang : public lldb_private::plugin::dwarf::DWARFASTParser {
+public:
+ DWARFASTParserClang(lldb_private::TypeSystemClang &ast);
+
+ ~DWARFASTParserClang() override;
+
+ // DWARFASTParser interface.
+ lldb::TypeSP
+ ParseTypeFromDWARF(const lldb_private::SymbolContext &sc,
+ const lldb_private::plugin::dwarf::DWARFDIE &die,
+ bool *type_is_new_ptr) override;
+
+ lldb_private::ConstString ConstructDemangledNameFromDWARF(
+ const lldb_private::plugin::dwarf::DWARFDIE &die) override;
+
+ lldb_private::Function *
+ ParseFunctionFromDWARF(lldb_private::CompileUnit &comp_unit,
+ const lldb_private::plugin::dwarf::DWARFDIE &die,
+ const lldb_private::AddressRange &func_range) override;
+
+ bool
+ CompleteTypeFromDWARF(const lldb_private::plugin::dwarf::DWARFDIE &die,
+ lldb_private::Type *type,
+ lldb_private::CompilerType &compiler_type) override;
+
+ lldb_private::CompilerDecl GetDeclForUIDFromDWARF(
+ const lldb_private::plugin::dwarf::DWARFDIE &die) override;
+
+ void EnsureAllDIEsInDeclContextHaveBeenParsed(
+ lldb_private::CompilerDeclContext decl_context) override;
+
+ lldb_private::CompilerDeclContext GetDeclContextForUIDFromDWARF(
+ const lldb_private::plugin::dwarf::DWARFDIE &die) override;
+
+ lldb_private::CompilerDeclContext GetDeclContextContainingUIDFromDWARF(
+ const lldb_private::plugin::dwarf::DWARFDIE &die) override;
+
+ lldb_private::ClangASTImporter &GetClangASTImporter();
+
+ /// Extracts an value for a given Clang integer type from a DWARFFormValue.
+ ///
+ /// \param int_type The Clang type that defines the bit size and signedness
+ /// of the integer that should be extracted. Has to be either
+ /// an integer type or an enum type. For enum types the
+ /// underlying integer type will be considered as the
+ /// expected integer type that should be extracted.
+ /// \param form_value The DWARFFormValue that contains the integer value.
+ /// \return An APInt containing the same integer value as the given
+ /// DWARFFormValue with the bit width of the given integer type.
+ /// Returns an error if the value in the DWARFFormValue does not fit
+ /// into the given integer type or the integer type isn't supported.
+ llvm::Expected<llvm::APInt> ExtractIntFromFormValue(
+ const lldb_private::CompilerType &int_type,
+ const lldb_private::plugin::dwarf::DWARFFormValue &form_value) const;
+
+ /// Returns the template parameters of a class DWARFDIE as a string.
+ ///
+ /// This is mostly useful for -gsimple-template-names which omits template
+ /// parameters from the DIE name and instead always adds template parameter
+ /// children DIEs.
+ ///
+ /// \param die The struct/class DWARFDIE containing template parameters.
+ /// \return A string, including surrounding '<>', of the template parameters.
+ /// If the DIE's name already has '<>', returns an empty string because
+ /// it's assumed that the caller is using the DIE name anyway.
+ std::string GetDIEClassTemplateParams(
+ const lldb_private::plugin::dwarf::DWARFDIE &die) override;
+
+ void MapDeclDIEToDefDIE(const lldb_private::plugin::dwarf::DWARFDIE &decl_die,
+ const lldb_private::plugin::dwarf::DWARFDIE &def_die);
+
+protected:
+ /// Protected typedefs and members.
+ /// @{
+ class DelayedAddObjCClassProperty;
+ typedef std::vector<DelayedAddObjCClassProperty> DelayedPropertyList;
+
+ typedef llvm::DenseMap<
+ const lldb_private::plugin::dwarf::DWARFDebugInfoEntry *,
+ clang::DeclContext *>
+ DIEToDeclContextMap;
+ typedef std::multimap<const clang::DeclContext *,
+ const lldb_private::plugin::dwarf::DWARFDIE>
+ DeclContextToDIEMap;
+ typedef llvm::DenseMap<
+ const lldb_private::plugin::dwarf::DWARFDebugInfoEntry *,
+ lldb_private::OptionalClangModuleID>
+ DIEToModuleMap;
+ typedef llvm::DenseMap<
+ const lldb_private::plugin::dwarf::DWARFDebugInfoEntry *, clang::Decl *>
+ DIEToDeclMap;
+
+ lldb_private::TypeSystemClang &m_ast;
+ DIEToDeclMap m_die_to_decl;
+ DIEToDeclContextMap m_die_to_decl_ctx;
+ DeclContextToDIEMap m_decl_ctx_to_die;
+ DIEToModuleMap m_die_to_module;
+ std::unique_ptr<lldb_private::ClangASTImporter> m_clang_ast_importer_up;
+ /// @}
+
+ clang::DeclContext *
+ GetDeclContextForBlock(const lldb_private::plugin::dwarf::DWARFDIE &die);
+
+ clang::BlockDecl *
+ ResolveBlockDIE(const lldb_private::plugin::dwarf::DWARFDIE &die);
+
+ clang::NamespaceDecl *
+ ResolveNamespaceDIE(const lldb_private::plugin::dwarf::DWARFDIE &die);
+
+ /// Returns the namespace decl that a DW_TAG_imported_declaration imports.
+ ///
+ /// \param[in] die The import declaration to resolve. If the DIE is not a
+ /// DW_TAG_imported_declaration the behaviour is undefined.
+ ///
+ /// \returns The decl corresponding to the namespace that the specified
+ /// 'die' imports. If the imported entity is not a namespace
+ /// or another import declaration, returns nullptr. If an error
+ /// occurs, returns nullptr.
+ clang::NamespaceDecl *ResolveImportedDeclarationDIE(
+ const lldb_private::plugin::dwarf::DWARFDIE &die);
+
+ bool ParseTemplateDIE(const lldb_private::plugin::dwarf::DWARFDIE &die,
+ lldb_private::TypeSystemClang::TemplateParameterInfos
+ &template_param_infos);
+
+ bool ParseTemplateParameterInfos(
+ const lldb_private::plugin::dwarf::DWARFDIE &parent_die,
+ lldb_private::TypeSystemClang::TemplateParameterInfos
+ &template_param_infos);
+
+ void GetUniqueTypeNameAndDeclaration(
+ const lldb_private::plugin::dwarf::DWARFDIE &die,
+ lldb::LanguageType language, lldb_private::ConstString &unique_typename,
+ lldb_private::Declaration &decl_declaration);
+
+ bool ParseChildMembers(
+ const lldb_private::plugin::dwarf::DWARFDIE &die,
+ lldb_private::CompilerType &class_compiler_type,
+ std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> &base_classes,
+ std::vector<lldb_private::plugin::dwarf::DWARFDIE> &member_function_dies,
+ std::vector<lldb_private::plugin::dwarf::DWARFDIE> &contained_type_dies,
+ DelayedPropertyList &delayed_properties,
+ const lldb::AccessType default_accessibility,
+ lldb_private::ClangASTImporter::LayoutInfo &layout_info);
+
+ size_t
+ ParseChildParameters(clang::DeclContext *containing_decl_ctx,
+ const lldb_private::plugin::dwarf::DWARFDIE &parent_die,
+ bool skip_artificial, bool &is_static, bool &is_variadic,
+ bool &has_template_params,
+ std::vector<lldb_private::CompilerType> &function_args,
+ std::vector<clang::ParmVarDecl *> &function_param_decls,
+ unsigned &type_quals);
+
+ size_t ParseChildEnumerators(
+ lldb_private::CompilerType &compiler_type, bool is_signed,
+ uint32_t enumerator_byte_size,
+ const lldb_private::plugin::dwarf::DWARFDIE &parent_die);
+
+ /// Parse a structure, class, or union type DIE.
+ lldb::TypeSP
+ ParseStructureLikeDIE(const lldb_private::SymbolContext &sc,
+ const lldb_private::plugin::dwarf::DWARFDIE &die,
+ ParsedDWARFTypeAttributes &attrs);
+
+ clang::Decl *
+ GetClangDeclForDIE(const lldb_private::plugin::dwarf::DWARFDIE &die);
+
+ clang::DeclContext *
+ GetClangDeclContextForDIE(const lldb_private::plugin::dwarf::DWARFDIE &die);
+
+ clang::DeclContext *GetClangDeclContextContainingDIE(
+ const lldb_private::plugin::dwarf::DWARFDIE &die,
+ lldb_private::plugin::dwarf::DWARFDIE *decl_ctx_die);
+ lldb_private::OptionalClangModuleID
+ GetOwningClangModule(const lldb_private::plugin::dwarf::DWARFDIE &die);
+
+ bool CopyUniqueClassMethodTypes(
+ const lldb_private::plugin::dwarf::DWARFDIE &src_class_die,
+ const lldb_private::plugin::dwarf::DWARFDIE &dst_class_die,
+ lldb_private::Type *class_type,
+ std::vector<lldb_private::plugin::dwarf::DWARFDIE> &failures);
+
+ clang::DeclContext *GetCachedClangDeclContextForDIE(
+ const lldb_private::plugin::dwarf::DWARFDIE &die);
+
+ void LinkDeclContextToDIE(clang::DeclContext *decl_ctx,
+ const lldb_private::plugin::dwarf::DWARFDIE &die);
+
+ void LinkDeclToDIE(clang::Decl *decl,
+ const lldb_private::plugin::dwarf::DWARFDIE &die);
+
+ /// If \p type_sp is valid, calculate and set its symbol context scope, and
+ /// update the type list for its backing symbol file.
+ ///
+ /// Returns \p type_sp.
+ lldb::TypeSP UpdateSymbolContextScopeForType(
+ const lldb_private::SymbolContext &sc,
+ const lldb_private::plugin::dwarf::DWARFDIE &die, lldb::TypeSP type_sp);
+
+ /// Follow Clang Module Skeleton CU references to find a type definition.
+ lldb::TypeSP
+ ParseTypeFromClangModule(const lldb_private::SymbolContext &sc,
+ const lldb_private::plugin::dwarf::DWARFDIE &die,
+ lldb_private::Log *log);
+
+ // Return true if this type is a declaration to a type in an external
+ // module.
+ lldb::ModuleSP
+ GetModuleForType(const lldb_private::plugin::dwarf::DWARFDIE &die);
+
+ static bool classof(const DWARFASTParser *Parser) {
+ return Parser->GetKind() == Kind::DWARFASTParserClang;
+ }
+
+private:
+ struct FieldInfo {
+ uint64_t bit_size = 0;
+ uint64_t bit_offset = 0;
+ bool is_bitfield = false;
+ bool is_artificial = false;
+
+ FieldInfo() = default;
+
+ void SetIsBitfield(bool flag) { is_bitfield = flag; }
+ bool IsBitfield() { return is_bitfield; }
+
+ void SetIsArtificial(bool flag) { is_artificial = flag; }
+ bool IsArtificial() const { return is_artificial; }
+
+ bool NextBitfieldOffsetIsValid(const uint64_t next_bit_offset) const {
+ // Any subsequent bitfields must not overlap and must be at a higher
+ // bit offset than any previous bitfield + size.
+ return (bit_size + bit_offset) <= next_bit_offset;
+ }
+ };
+
+ /// Parsed form of all attributes that are relevant for parsing type members.
+ struct MemberAttributes {
+ explicit MemberAttributes(
+ const lldb_private::plugin::dwarf::DWARFDIE &die,
+ const lldb_private::plugin::dwarf::DWARFDIE &parent_die,
+ lldb::ModuleSP module_sp);
+ const char *name = nullptr;
+ /// Indicates how many bits into the word (according to the host endianness)
+ /// the low-order bit of the field starts. Can be negative.
+ int64_t bit_offset = 0;
+ /// Indicates the size of the field in bits.
+ size_t bit_size = 0;
+ uint64_t data_bit_offset = UINT64_MAX;
+ lldb::AccessType accessibility = lldb::eAccessNone;
+ std::optional<uint64_t> byte_size;
+ std::optional<lldb_private::plugin::dwarf::DWARFFormValue> const_value_form;
+ lldb_private::plugin::dwarf::DWARFFormValue encoding_form;
+ /// Indicates the byte offset of the word from the base address of the
+ /// structure.
+ uint32_t member_byte_offset = UINT32_MAX;
+ bool is_artificial = false;
+ bool is_declaration = false;
+ };
+
+ /// Returns 'true' if we should create an unnamed bitfield
+ /// and add it to the parser's current AST.
+ ///
+ /// \param[in] last_field_info FieldInfo of the previous DW_TAG_member
+ /// we parsed.
+ /// \param[in] last_field_end Offset (in bits) where the last parsed field
+ /// ended.
+ /// \param[in] this_field_info FieldInfo of the current DW_TAG_member
+ /// being parsed.
+ /// \param[in] layout_info Layout information of all decls parsed by the
+ /// current parser.
+ bool ShouldCreateUnnamedBitfield(
+ FieldInfo const &last_field_info, uint64_t last_field_end,
+ FieldInfo const &this_field_info,
+ lldb_private::ClangASTImporter::LayoutInfo const &layout_info) const;
+
+ /// Parses a DW_TAG_APPLE_property DIE and appends the parsed data to the
+ /// list of delayed Objective-C properties.
+ ///
+ /// Note: The delayed property needs to be finalized to actually create the
+ /// property declarations in the module AST.
+ ///
+ /// \param die The DW_TAG_APPLE_property DIE that will be parsed.
+ /// \param parent_die The parent DIE.
+ /// \param class_clang_type The Objective-C class that will contain the
+ /// created property.
+ /// \param delayed_properties The list of delayed properties that the result
+ /// will be appended to.
+ void
+ ParseObjCProperty(const lldb_private::plugin::dwarf::DWARFDIE &die,
+ const lldb_private::plugin::dwarf::DWARFDIE &parent_die,
+ const lldb_private::CompilerType &class_clang_type,
+ DelayedPropertyList &delayed_properties);
+
+ void
+ ParseSingleMember(const lldb_private::plugin::dwarf::DWARFDIE &die,
+ const lldb_private::plugin::dwarf::DWARFDIE &parent_die,
+ const lldb_private::CompilerType &class_clang_type,
+ lldb::AccessType default_accessibility,
+ lldb_private::ClangASTImporter::LayoutInfo &layout_info,
+ FieldInfo &last_field_info);
+
+ /// If the specified 'die' represents a static data member, creates
+ /// a 'clang::VarDecl' for it and attaches it to specified parent
+ /// 'class_clang_type'.
+ ///
+ /// \param[in] die The member declaration we want to create a
+ /// clang::VarDecl for.
+ ///
+ /// \param[in] attrs The parsed attributes for the specified 'die'.
+ ///
+ /// \param[in] class_clang_type The parent RecordType of the static
+ /// member this function will create.
+ void CreateStaticMemberVariable(
+ const lldb_private::plugin::dwarf::DWARFDIE &die,
+ const MemberAttributes &attrs,
+ const lldb_private::CompilerType &class_clang_type);
+
+ bool CompleteRecordType(const lldb_private::plugin::dwarf::DWARFDIE &die,
+ lldb_private::Type *type,
+ lldb_private::CompilerType &clang_type);
+ bool CompleteEnumType(const lldb_private::plugin::dwarf::DWARFDIE &die,
+ lldb_private::Type *type,
+ lldb_private::CompilerType &clang_type);
+
+ lldb::TypeSP
+ ParseTypeModifier(const lldb_private::SymbolContext &sc,
+ const lldb_private::plugin::dwarf::DWARFDIE &die,
+ ParsedDWARFTypeAttributes &attrs);
+ lldb::TypeSP ParseEnum(const lldb_private::SymbolContext &sc,
+ const lldb_private::plugin::dwarf::DWARFDIE &die,
+ ParsedDWARFTypeAttributes &attrs);
+ lldb::TypeSP ParseSubroutine(const lldb_private::plugin::dwarf::DWARFDIE &die,
+ const ParsedDWARFTypeAttributes &attrs);
+
+ /// Helper function called by \ref ParseSubroutine when parsing ObjC-methods.
+ ///
+ /// \param[in] objc_method Name of the ObjC method being parsed.
+ ///
+ /// \param[in] die The DIE that represents the ObjC method being parsed.
+ ///
+ /// \param[in] clang_type The CompilerType representing the function prototype
+ /// of the ObjC method being parsed.
+ ///
+ /// \param[in] attrs DWARF attributes for \ref die.
+ ///
+ /// \param[in] is_variadic Is true iff we're parsing a variadic method.
+ ///
+ /// \returns true on success
+ bool
+ ParseObjCMethod(const lldb_private::ObjCLanguage::MethodName &objc_method,
+ const lldb_private::plugin::dwarf::DWARFDIE &die,
+ lldb_private::CompilerType clang_type,
+ const ParsedDWARFTypeAttributes &attrs, bool is_variadic);
+
+ /// Helper function called by \ref ParseSubroutine when parsing C++ methods.
+ ///
+ /// \param[in] die The DIE that represents the C++ method being parsed.
+ ///
+ /// \param[in] clang_type The CompilerType representing the function prototype
+ /// of the C++ method being parsed.
+ ///
+ /// \param[in] attrs DWARF attributes for \ref die.
+ ///
+ /// \param[in] decl_ctx_die The DIE representing the DeclContext of the C++
+ /// method being parsed.
+ ///
+ /// \param[in] is_static Is true iff we're parsing a static method.
+ ///
+ /// \param[out] ignore_containing_context Will get set to true if the caller
+ /// should treat this C++ method as-if it was not a C++ method.
+ /// Currently used as a hack to work around templated C++ methods
+ /// causing class definitions to mismatch between CUs.
+ ///
+ /// \returns A pair of <bool, TypeSP>. The first element is 'true' on success.
+ /// The second element is non-null if we have previously parsed this
+ /// method (a null TypeSP does not indicate failure).
+ std::pair<bool, lldb::TypeSP>
+ ParseCXXMethod(const lldb_private::plugin::dwarf::DWARFDIE &die,
+ lldb_private::CompilerType clang_type,
+ const ParsedDWARFTypeAttributes &attrs,
+ const lldb_private::plugin::dwarf::DWARFDIE &decl_ctx_die,
+ bool is_static, bool &ignore_containing_context);
+
+ lldb::TypeSP ParseArrayType(const lldb_private::plugin::dwarf::DWARFDIE &die,
+ const ParsedDWARFTypeAttributes &attrs);
+ lldb::TypeSP
+ ParsePointerToMemberType(const lldb_private::plugin::dwarf::DWARFDIE &die,
+ const ParsedDWARFTypeAttributes &attrs);
+
+ /// Parses a DW_TAG_inheritance DIE into a base/super class.
+ ///
+ /// \param die The DW_TAG_inheritance DIE to parse.
+ /// \param parent_die The parent DIE of the given DIE.
+ /// \param class_clang_type The C++/Objective-C class representing parent_die.
+ /// For an Objective-C class this method sets the super class on success. For
+ /// a C++ class this will *not* add the result as a base class.
+ /// \param default_accessibility The default accessibility that is given to
+ /// base classes if they don't have an explicit accessibility set.
+ /// \param module_sp The current Module.
+ /// \param base_classes The list of C++ base classes that will be appended
+ /// with the parsed base class on success.
+ /// \param layout_info The layout information that will be updated for C++
+ /// base classes with the base offset.
+ void ParseInheritance(
+ const lldb_private::plugin::dwarf::DWARFDIE &die,
+ const lldb_private::plugin::dwarf::DWARFDIE &parent_die,
+ const lldb_private::CompilerType class_clang_type,
+ const lldb::AccessType default_accessibility,
+ const lldb::ModuleSP &module_sp,
+ std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> &base_classes,
+ lldb_private::ClangASTImporter::LayoutInfo &layout_info);
+
+ /// Parses DW_TAG_variant_part DIE into a structure that encodes all variants
+ /// Note that this is currently being emitted by rustc and not Clang
+ /// \param die DW_TAG_variant_part DIE to parse
+ /// \param parent_die The parent DW_TAG_structure_type to parse
+ /// \param class_clang_type The Rust struct representing parent_die.
+ /// \param default_accesibility The default accessibility that is given to
+ /// base classes if they don't have an explicit accessibility set
+ /// \param layout_info The layout information that will be updated for
+ // base classes with the base offset
+ void
+ ParseRustVariantPart(lldb_private::plugin::dwarf::DWARFDIE &die,
+ const lldb_private::plugin::dwarf::DWARFDIE &parent_die,
+ lldb_private::CompilerType &class_clang_type,
+ const lldb::AccessType default_accesibility,
+ lldb_private::ClangASTImporter::LayoutInfo &layout_info);
+};
+
+/// Parsed form of all attributes that are relevant for type reconstruction.
+/// Some attributes are relevant for all kinds of types (declaration), while
+/// others are only meaningful to a specific type (is_virtual)
+struct ParsedDWARFTypeAttributes {
+ explicit ParsedDWARFTypeAttributes(
+ const lldb_private::plugin::dwarf::DWARFDIE &die);
+
+ lldb::AccessType accessibility = lldb::eAccessNone;
+ bool is_artificial = false;
+ bool is_complete_objc_class = false;
+ bool is_explicit = false;
+ bool is_forward_declaration = false;
+ bool is_inline = false;
+ bool is_scoped_enum = false;
+ bool is_vector = false;
+ bool is_virtual = false;
+ bool is_objc_direct_call = false;
+ bool exports_symbols = false;
+ clang::StorageClass storage = clang::SC_None;
+ const char *mangled_name = nullptr;
+ lldb_private::ConstString name;
+ lldb_private::Declaration decl;
+ lldb_private::plugin::dwarf::DWARFDIE object_pointer;
+ lldb_private::plugin::dwarf::DWARFFormValue abstract_origin;
+ lldb_private::plugin::dwarf::DWARFFormValue containing_type;
+ lldb_private::plugin::dwarf::DWARFFormValue signature;
+ lldb_private::plugin::dwarf::DWARFFormValue specification;
+ lldb_private::plugin::dwarf::DWARFFormValue type;
+ lldb::LanguageType class_language = lldb::eLanguageTypeUnknown;
+ std::optional<uint64_t> byte_size;
+ std::optional<uint64_t> alignment;
+ size_t calling_convention = llvm::dwarf::DW_CC_normal;
+ uint32_t bit_stride = 0;
+ uint32_t byte_stride = 0;
+ uint32_t encoding = 0;
+ clang::RefQualifierKind ref_qual =
+ clang::RQ_None; ///< Indicates ref-qualifier of
+ ///< C++ member function if present.
+ ///< Is RQ_None otherwise.
+};
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFASTPARSERCLANG_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp
new file mode 100644
index 000000000000..3d35775e081e
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp
@@ -0,0 +1,66 @@
+//===-- DWARFAttribute.cpp ------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFAttribute.h"
+#include "DWARFUnit.h"
+#include "DWARFDebugInfo.h"
+
+using namespace lldb_private::dwarf;
+using namespace lldb_private::plugin::dwarf;
+
+DWARFAttributes::DWARFAttributes() : m_infos() {}
+
+DWARFAttributes::~DWARFAttributes() = default;
+
+uint32_t DWARFAttributes::FindAttributeIndex(dw_attr_t attr) const {
+ collection::const_iterator end = m_infos.end();
+ collection::const_iterator beg = m_infos.begin();
+ collection::const_iterator pos;
+ for (pos = beg; pos != end; ++pos) {
+ if (pos->attr.get_attr() == attr)
+ return std::distance(beg, pos);
+ }
+ return UINT32_MAX;
+}
+
+void DWARFAttributes::Append(const DWARFFormValue &form_value,
+ dw_offset_t attr_die_offset, dw_attr_t attr) {
+ AttributeValue attr_value = {const_cast<DWARFUnit *>(form_value.GetUnit()),
+ attr_die_offset,
+ {attr, form_value.Form(), form_value.Value()}};
+ m_infos.push_back(attr_value);
+}
+
+bool DWARFAttributes::ExtractFormValueAtIndex(
+ uint32_t i, DWARFFormValue &form_value) const {
+ const DWARFUnit *cu = CompileUnitAtIndex(i);
+ form_value.SetUnit(cu);
+ form_value.SetForm(FormAtIndex(i));
+ if (form_value.Form() == DW_FORM_implicit_const) {
+ form_value.SetValue(ValueAtIndex(i));
+ return true;
+ }
+ lldb::offset_t offset = DIEOffsetAtIndex(i);
+ return form_value.ExtractValue(cu->GetData(), &offset);
+}
+
+DWARFDIE
+DWARFAttributes::FormValueAsReference(dw_attr_t attr) const {
+ const uint32_t attr_idx = FindAttributeIndex(attr);
+ if (attr_idx != UINT32_MAX)
+ return FormValueAsReferenceAtIndex(attr_idx);
+ return {};
+}
+
+DWARFDIE
+DWARFAttributes::FormValueAsReferenceAtIndex(uint32_t i) const {
+ DWARFFormValue form_value;
+ if (ExtractFormValueAtIndex(i, form_value))
+ return form_value.Reference();
+ return {};
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h
new file mode 100644
index 000000000000..e05ccc980d92
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h
@@ -0,0 +1,81 @@
+//===-- DWARFAttribute.h ----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFATTRIBUTE_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFATTRIBUTE_H
+
+#include "DWARFDefines.h"
+#include "DWARFFormValue.h"
+#include "llvm/ADT/SmallVector.h"
+#include <vector>
+
+namespace lldb_private::plugin {
+namespace dwarf {
+class DWARFUnit;
+
+class DWARFAttribute {
+public:
+ DWARFAttribute(dw_attr_t attr, dw_form_t form,
+ DWARFFormValue::ValueType value)
+ : m_attr(attr), m_form(form), m_value(value) {}
+
+ dw_attr_t get_attr() const { return m_attr; }
+ dw_form_t get_form() const { return m_form; }
+ DWARFFormValue::ValueType get_value() const { return m_value; }
+ void get(dw_attr_t &attr, dw_form_t &form,
+ DWARFFormValue::ValueType &val) const {
+ attr = m_attr;
+ form = m_form;
+ val = m_value;
+ }
+
+protected:
+ dw_attr_t m_attr;
+ dw_form_t m_form;
+ DWARFFormValue::ValueType m_value;
+};
+
+class DWARFAttributes {
+public:
+ DWARFAttributes();
+ ~DWARFAttributes();
+
+ void Append(const DWARFFormValue &form_value, dw_offset_t attr_die_offset,
+ dw_attr_t attr);
+ DWARFUnit *CompileUnitAtIndex(uint32_t i) const { return m_infos[i].cu; }
+ dw_offset_t DIEOffsetAtIndex(uint32_t i) const {
+ return m_infos[i].die_offset;
+ }
+ dw_attr_t AttributeAtIndex(uint32_t i) const {
+ return m_infos[i].attr.get_attr();
+ }
+ dw_form_t FormAtIndex(uint32_t i) const { return m_infos[i].attr.get_form(); }
+ DWARFFormValue::ValueType ValueAtIndex(uint32_t i) const {
+ return m_infos[i].attr.get_value();
+ }
+ bool ExtractFormValueAtIndex(uint32_t i, DWARFFormValue &form_value) const;
+ DWARFDIE FormValueAsReferenceAtIndex(uint32_t i) const;
+ DWARFDIE FormValueAsReference(dw_attr_t attr) const;
+ uint32_t FindAttributeIndex(dw_attr_t attr) const;
+ void Clear() { m_infos.clear(); }
+ size_t Size() const { return m_infos.size(); }
+
+protected:
+ struct AttributeValue {
+ DWARFUnit *cu; // Keep the compile unit with each attribute in
+ // case we have DW_FORM_ref_addr values
+ dw_offset_t die_offset;
+ DWARFAttribute attr;
+ };
+ typedef llvm::SmallVector<AttributeValue, 8> collection;
+ collection m_infos;
+};
+} // namespace dwarf
+} // namespace lldb_private::plugin
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFATTRIBUTE_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.cpp
new file mode 100644
index 000000000000..c2ebeed4c860
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.cpp
@@ -0,0 +1,136 @@
+//===-- DWARFBaseDIE.cpp --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFBaseDIE.h"
+
+#include "DWARFUnit.h"
+#include "DWARFDebugInfoEntry.h"
+#include "SymbolFileDWARF.h"
+
+#include "lldb/Core/Module.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Utility/Log.h"
+#include <optional>
+
+using namespace lldb_private;
+using namespace lldb_private::plugin::dwarf;
+
+std::optional<DIERef> DWARFBaseDIE::GetDIERef() const {
+ if (!IsValid())
+ return std::nullopt;
+
+ return DIERef(m_cu->GetSymbolFileDWARF().GetFileIndex(),
+ m_cu->GetDebugSection(), m_die->GetOffset());
+}
+
+dw_tag_t DWARFBaseDIE::Tag() const {
+ if (m_die)
+ return m_die->Tag();
+ else
+ return llvm::dwarf::DW_TAG_null;
+}
+
+const char *DWARFBaseDIE::GetAttributeValueAsString(const dw_attr_t attr,
+ const char *fail_value) const {
+ if (IsValid())
+ return m_die->GetAttributeValueAsString(GetCU(), attr, fail_value);
+ else
+ return fail_value;
+}
+
+uint64_t DWARFBaseDIE::GetAttributeValueAsUnsigned(const dw_attr_t attr,
+ uint64_t fail_value) const {
+ if (IsValid())
+ return m_die->GetAttributeValueAsUnsigned(GetCU(), attr, fail_value);
+ else
+ return fail_value;
+}
+
+std::optional<uint64_t>
+DWARFBaseDIE::GetAttributeValueAsOptionalUnsigned(const dw_attr_t attr) const {
+ if (IsValid())
+ return m_die->GetAttributeValueAsOptionalUnsigned(GetCU(), attr);
+ return std::nullopt;
+}
+
+uint64_t DWARFBaseDIE::GetAttributeValueAsAddress(const dw_attr_t attr,
+ uint64_t fail_value) const {
+ if (IsValid())
+ return m_die->GetAttributeValueAsAddress(GetCU(), attr, fail_value);
+ else
+ return fail_value;
+}
+
+lldb::user_id_t DWARFBaseDIE::GetID() const {
+ const std::optional<DIERef> &ref = this->GetDIERef();
+ if (ref)
+ return ref->get_id();
+
+ return LLDB_INVALID_UID;
+}
+
+const char *DWARFBaseDIE::GetName() const {
+ if (IsValid())
+ return m_die->GetName(m_cu);
+ else
+ return nullptr;
+}
+
+lldb::ModuleSP DWARFBaseDIE::GetModule() const {
+ SymbolFileDWARF *dwarf = GetDWARF();
+ if (dwarf)
+ return dwarf->GetObjectFile()->GetModule();
+ else
+ return lldb::ModuleSP();
+}
+
+dw_offset_t DWARFBaseDIE::GetOffset() const {
+ if (IsValid())
+ return m_die->GetOffset();
+ else
+ return DW_INVALID_OFFSET;
+}
+
+SymbolFileDWARF *DWARFBaseDIE::GetDWARF() const {
+ if (m_cu)
+ return &m_cu->GetSymbolFileDWARF();
+ else
+ return nullptr;
+}
+
+bool DWARFBaseDIE::HasChildren() const {
+ return m_die && m_die->HasChildren();
+}
+
+bool DWARFBaseDIE::Supports_DW_AT_APPLE_objc_complete_type() const {
+ return IsValid() && GetDWARF()->Supports_DW_AT_APPLE_objc_complete_type(m_cu);
+}
+
+DWARFAttributes DWARFBaseDIE::GetAttributes(Recurse recurse) const {
+ if (IsValid())
+ return m_die->GetAttributes(m_cu, recurse);
+ return DWARFAttributes();
+}
+
+namespace lldb_private::plugin {
+namespace dwarf {
+bool operator==(const DWARFBaseDIE &lhs, const DWARFBaseDIE &rhs) {
+ return lhs.GetDIE() == rhs.GetDIE() && lhs.GetCU() == rhs.GetCU();
+}
+
+bool operator!=(const DWARFBaseDIE &lhs, const DWARFBaseDIE &rhs) {
+ return !(lhs == rhs);
+}
+} // namespace dwarf
+} // namespace lldb_private::plugin
+
+const DWARFDataExtractor &DWARFBaseDIE::GetData() const {
+ // Clients must check if this DIE is valid before calling this function.
+ assert(IsValid());
+ return m_cu->GetData();
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h
new file mode 100644
index 000000000000..235343d22712
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h
@@ -0,0 +1,130 @@
+//===-- DWARFBaseDIE.h -----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFBASEDIE_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFBASEDIE_H
+
+#include "lldb/Core/dwarf.h"
+#include "lldb/lldb-types.h"
+
+#include "llvm/Support/Error.h"
+#include <optional>
+
+namespace lldb_private::plugin {
+namespace dwarf {
+class DIERef;
+class DWARFASTParser;
+class DWARFAttributes;
+class DWARFUnit;
+class DWARFDebugInfoEntry;
+class DWARFDeclContext;
+class SymbolFileDWARF;
+
+class DWARFBaseDIE {
+public:
+ DWARFBaseDIE() = default;
+
+ DWARFBaseDIE(DWARFUnit *cu, DWARFDebugInfoEntry *die)
+ : m_cu(cu), m_die(die) {}
+
+ DWARFBaseDIE(const DWARFUnit *cu, DWARFDebugInfoEntry *die)
+ : m_cu(const_cast<DWARFUnit *>(cu)), m_die(die) {}
+
+ DWARFBaseDIE(DWARFUnit *cu, const DWARFDebugInfoEntry *die)
+ : m_cu(cu), m_die(const_cast<DWARFDebugInfoEntry *>(die)) {}
+
+ DWARFBaseDIE(const DWARFUnit *cu, const DWARFDebugInfoEntry *die)
+ : m_cu(const_cast<DWARFUnit *>(cu)),
+ m_die(const_cast<DWARFDebugInfoEntry *>(die)) {}
+
+ // Tests
+ explicit operator bool() const { return IsValid(); }
+
+ bool IsValid() const { return m_cu && m_die; }
+
+ bool HasChildren() const;
+
+ bool Supports_DW_AT_APPLE_objc_complete_type() const;
+
+ // Accessors
+ SymbolFileDWARF *GetDWARF() const;
+
+ DWARFUnit *GetCU() const { return m_cu; }
+
+ DWARFDebugInfoEntry *GetDIE() const { return m_die; }
+
+ std::optional<DIERef> GetDIERef() const;
+
+ void Set(DWARFUnit *cu, DWARFDebugInfoEntry *die) {
+ if (cu && die) {
+ m_cu = cu;
+ m_die = die;
+ } else {
+ Clear();
+ }
+ }
+
+ void Clear() {
+ m_cu = nullptr;
+ m_die = nullptr;
+ }
+
+ // Get the data that contains the attribute values for this DIE. Support
+ // for .debug_types means that any DIE can have its data either in the
+ // .debug_info or the .debug_types section; this method will return the
+ // correct section data.
+ //
+ // Clients must validate that this object is valid before calling this.
+ const DWARFDataExtractor &GetData() const;
+
+ // Accessing information about a DIE
+ dw_tag_t Tag() const;
+
+ dw_offset_t GetOffset() const;
+
+ // Get the LLDB user ID for this DIE. This is often just the DIE offset,
+ // but it might have a SymbolFileDWARF::GetID() in the high 32 bits if
+ // we are doing Darwin DWARF in .o file, or DWARF stand alone debug
+ // info.
+ lldb::user_id_t GetID() const;
+
+ const char *GetName() const;
+
+ lldb::ModuleSP GetModule() const;
+
+ // Getting attribute values from the DIE.
+ //
+ // GetAttributeValueAsXXX() functions should only be used if you are
+ // looking for one or two attributes on a DIE. If you are trying to
+ // parse all attributes, use GetAttributes (...) instead
+ const char *GetAttributeValueAsString(const dw_attr_t attr,
+ const char *fail_value) const;
+
+ uint64_t GetAttributeValueAsUnsigned(const dw_attr_t attr,
+ uint64_t fail_value) const;
+
+ std::optional<uint64_t>
+ GetAttributeValueAsOptionalUnsigned(const dw_attr_t attr) const;
+
+ uint64_t GetAttributeValueAsAddress(const dw_attr_t attr,
+ uint64_t fail_value) const;
+
+ enum class Recurse : bool { no, yes };
+ DWARFAttributes GetAttributes(Recurse recurse = Recurse::yes) const;
+
+protected:
+ DWARFUnit *m_cu = nullptr;
+ DWARFDebugInfoEntry *m_die = nullptr;
+};
+
+bool operator==(const DWARFBaseDIE &lhs, const DWARFBaseDIE &rhs);
+bool operator!=(const DWARFBaseDIE &lhs, const DWARFBaseDIE &rhs);
+} // namespace dwarf
+} // namespace lldb_private::plugin
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFBASEDIE_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp
new file mode 100644
index 000000000000..ec4c297cf7e1
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp
@@ -0,0 +1,108 @@
+//===-- DWARFCompileUnit.cpp ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFCompileUnit.h"
+#include "DWARFDebugAranges.h"
+#include "SymbolFileDWARFDebugMap.h"
+
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/LineTable.h"
+#include "lldb/Utility/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::plugin::dwarf;
+
+void DWARFCompileUnit::Dump(Stream *s) const {
+ s->Format(
+
+ "{0:x16}: Compile Unit: length = {1:x8}, version = {2:x}, "
+ "abbr_offset = {3:x8}, addr_size = {4:x2} (next CU at "
+ "[{5:x16}])\n",
+ GetOffset(), GetLength(), GetVersion(), (uint32_t)GetAbbrevOffset(),
+ GetAddressByteSize(), GetNextUnitOffset());
+}
+
+void DWARFCompileUnit::BuildAddressRangeTable(
+ DWARFDebugAranges *debug_aranges) {
+ // This function is usually called if there in no .debug_aranges section in
+ // order to produce a compile unit level set of address ranges that is
+ // accurate.
+
+ size_t num_debug_aranges = debug_aranges->GetNumRanges();
+
+ // First get the compile unit DIE only and check contains ranges information.
+ const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly();
+
+ const dw_offset_t cu_offset = GetOffset();
+ if (die) {
+ DWARFRangeList ranges =
+ die->GetAttributeAddressRanges(this, /*check_hi_lo_pc=*/true);
+ for (const DWARFRangeList::Entry &range : ranges)
+ debug_aranges->AppendRange(cu_offset, range.GetRangeBase(),
+ range.GetRangeEnd());
+
+ if (!ranges.IsEmpty())
+ return;
+ }
+
+ if (debug_aranges->GetNumRanges() == num_debug_aranges) {
+ // We got nothing from the debug info, try to build the arange table from
+ // the debug map OSO aranges.
+ SymbolContext sc;
+ sc.comp_unit = m_dwarf.GetCompUnitForDWARFCompUnit(*this);
+ if (sc.comp_unit) {
+ SymbolFileDWARFDebugMap *debug_map_sym_file =
+ m_dwarf.GetDebugMapSymfile();
+ if (debug_map_sym_file) {
+ auto *cu_info =
+ debug_map_sym_file->GetCompileUnitInfo(&GetSymbolFileDWARF());
+ // If there are extra compile units the OSO entries aren't a reliable
+ // source of information.
+ if (cu_info->compile_units_sps.empty())
+ debug_map_sym_file->AddOSOARanges(&m_dwarf, debug_aranges);
+ }
+ }
+ }
+
+ if (debug_aranges->GetNumRanges() == num_debug_aranges) {
+ // We got nothing from the functions, maybe we have a line tables only
+ // situation. Check the line tables and build the arange table from this.
+ SymbolContext sc;
+ sc.comp_unit = m_dwarf.GetCompUnitForDWARFCompUnit(*this);
+ if (sc.comp_unit) {
+ if (LineTable *line_table = sc.comp_unit->GetLineTable()) {
+ LineTable::FileAddressRanges file_ranges;
+ const bool append = true;
+ const size_t num_ranges =
+ line_table->GetContiguousFileAddressRanges(file_ranges, append);
+ for (uint32_t idx = 0; idx < num_ranges; ++idx) {
+ const LineTable::FileAddressRanges::Entry &range =
+ file_ranges.GetEntryRef(idx);
+ debug_aranges->AppendRange(GetOffset(), range.GetRangeBase(),
+ range.GetRangeEnd());
+ }
+ }
+ }
+ }
+}
+
+DWARFCompileUnit &DWARFCompileUnit::GetNonSkeletonUnit() {
+ return llvm::cast<DWARFCompileUnit>(DWARFUnit::GetNonSkeletonUnit());
+}
+
+DWARFDIE DWARFCompileUnit::LookupAddress(const dw_addr_t address) {
+ if (DIE()) {
+ const DWARFDebugAranges &func_aranges = GetFunctionAranges();
+
+ // Re-check the aranges auto pointer contents in case it was created above
+ if (!func_aranges.IsEmpty())
+ return GetDIE(func_aranges.FindAddress(address));
+ }
+ return DWARFDIE();
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h
new file mode 100644
index 000000000000..b8344f548ac3
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h
@@ -0,0 +1,48 @@
+//===-- DWARFCompileUnit.h --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFCOMPILEUNIT_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFCOMPILEUNIT_H
+
+#include "DWARFUnit.h"
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+class DWARFAbbreviationDeclarationSet;
+} // namespace llvm
+
+namespace lldb_private::plugin {
+namespace dwarf {
+class DWARFCompileUnit : public DWARFUnit {
+public:
+ void BuildAddressRangeTable(DWARFDebugAranges *debug_aranges) override;
+
+ void Dump(Stream *s) const override;
+
+ static bool classof(const DWARFUnit *unit) { return !unit->IsTypeUnit(); }
+
+ DWARFCompileUnit &GetNonSkeletonUnit();
+
+ DWARFDIE LookupAddress(const dw_addr_t address);
+
+private:
+ DWARFCompileUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid,
+ const llvm::DWARFUnitHeader &header,
+ const llvm::DWARFAbbreviationDeclarationSet &abbrevs,
+ DIERef::Section section, bool is_dwo)
+ : DWARFUnit(dwarf, uid, header, abbrevs, section, is_dwo) {}
+
+ DWARFCompileUnit(const DWARFCompileUnit &) = delete;
+ const DWARFCompileUnit &operator=(const DWARFCompileUnit &) = delete;
+
+ friend class DWARFUnit;
+};
+} // namespace dwarf
+} // namespace lldb_private::plugin
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFCOMPILEUNIT_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.cpp
new file mode 100644
index 000000000000..e3872dc626be
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.cpp
@@ -0,0 +1,152 @@
+//===-- DWARFContext.cpp --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFContext.h"
+
+#include "lldb/Core/Section.h"
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::plugin::dwarf;
+
+static DWARFDataExtractor LoadSection(SectionList *section_list,
+ SectionType section_type) {
+ if (!section_list)
+ return DWARFDataExtractor();
+
+ auto section_sp = section_list->FindSectionByType(section_type, true);
+ if (!section_sp)
+ return DWARFDataExtractor();
+
+ DWARFDataExtractor data;
+ section_sp->GetSectionData(data);
+ return data;
+}
+
+const DWARFDataExtractor &
+DWARFContext::LoadOrGetSection(std::optional<SectionType> main_section_type,
+ std::optional<SectionType> dwo_section_type,
+ SectionData &data) {
+ llvm::call_once(data.flag, [&] {
+ if (dwo_section_type && isDwo())
+ data.data = LoadSection(m_dwo_section_list, *dwo_section_type);
+ else if (main_section_type)
+ data.data = LoadSection(m_main_section_list, *main_section_type);
+ });
+ return data.data;
+}
+
+const DWARFDataExtractor &DWARFContext::getOrLoadCuIndexData() {
+ return LoadOrGetSection(std::nullopt, eSectionTypeDWARFDebugCuIndex,
+ m_data_debug_cu_index);
+}
+
+const DWARFDataExtractor &DWARFContext::getOrLoadTuIndexData() {
+ return LoadOrGetSection(std::nullopt, eSectionTypeDWARFDebugTuIndex,
+ m_data_debug_tu_index);
+}
+
+const DWARFDataExtractor &DWARFContext::getOrLoadAbbrevData() {
+ return LoadOrGetSection(eSectionTypeDWARFDebugAbbrev,
+ eSectionTypeDWARFDebugAbbrevDwo, m_data_debug_abbrev);
+}
+
+const DWARFDataExtractor &DWARFContext::getOrLoadArangesData() {
+ return LoadOrGetSection(eSectionTypeDWARFDebugAranges, std::nullopt,
+ m_data_debug_aranges);
+}
+
+const DWARFDataExtractor &DWARFContext::getOrLoadAddrData() {
+ return LoadOrGetSection(eSectionTypeDWARFDebugAddr, std::nullopt,
+ m_data_debug_addr);
+}
+
+const DWARFDataExtractor &DWARFContext::getOrLoadDebugInfoData() {
+ return LoadOrGetSection(eSectionTypeDWARFDebugInfo,
+ eSectionTypeDWARFDebugInfoDwo, m_data_debug_info);
+}
+
+const DWARFDataExtractor &DWARFContext::getOrLoadLineData() {
+ return LoadOrGetSection(eSectionTypeDWARFDebugLine, std::nullopt,
+ m_data_debug_line);
+}
+
+const DWARFDataExtractor &DWARFContext::getOrLoadLineStrData() {
+ return LoadOrGetSection(eSectionTypeDWARFDebugLineStr, std::nullopt,
+ m_data_debug_line_str);
+}
+
+const DWARFDataExtractor &DWARFContext::getOrLoadLocData() {
+ return LoadOrGetSection(eSectionTypeDWARFDebugLoc,
+ eSectionTypeDWARFDebugLocDwo, m_data_debug_loc);
+}
+
+const DWARFDataExtractor &DWARFContext::getOrLoadLocListsData() {
+ return LoadOrGetSection(eSectionTypeDWARFDebugLocLists,
+ eSectionTypeDWARFDebugLocListsDwo,
+ m_data_debug_loclists);
+}
+
+const DWARFDataExtractor &DWARFContext::getOrLoadMacroData() {
+ return LoadOrGetSection(eSectionTypeDWARFDebugMacro, std::nullopt,
+ m_data_debug_macro);
+}
+
+const DWARFDataExtractor &DWARFContext::getOrLoadRangesData() {
+ return LoadOrGetSection(eSectionTypeDWARFDebugRanges, std::nullopt,
+ m_data_debug_ranges);
+}
+
+const DWARFDataExtractor &DWARFContext::getOrLoadRngListsData() {
+ return LoadOrGetSection(eSectionTypeDWARFDebugRngLists,
+ eSectionTypeDWARFDebugRngListsDwo,
+ m_data_debug_rnglists);
+}
+
+const DWARFDataExtractor &DWARFContext::getOrLoadStrData() {
+ return LoadOrGetSection(eSectionTypeDWARFDebugStr,
+ eSectionTypeDWARFDebugStrDwo, m_data_debug_str);
+}
+
+const DWARFDataExtractor &DWARFContext::getOrLoadStrOffsetsData() {
+ return LoadOrGetSection(eSectionTypeDWARFDebugStrOffsets,
+ eSectionTypeDWARFDebugStrOffsetsDwo,
+ m_data_debug_str_offsets);
+}
+
+const DWARFDataExtractor &DWARFContext::getOrLoadDebugTypesData() {
+ return LoadOrGetSection(eSectionTypeDWARFDebugTypes,
+ eSectionTypeDWARFDebugTypesDwo, m_data_debug_types);
+}
+
+llvm::DWARFContext &DWARFContext::GetAsLLVM() {
+ if (!m_llvm_context) {
+ llvm::StringMap<std::unique_ptr<llvm::MemoryBuffer>> section_map;
+ uint8_t addr_size = 0;
+ auto AddSection = [&](llvm::StringRef name, DWARFDataExtractor data) {
+ // Set the address size the first time we see it.
+ if (addr_size == 0)
+ addr_size = data.GetAddressByteSize();
+
+ section_map.try_emplace(
+ name, llvm::MemoryBuffer::getMemBuffer(toStringRef(data.GetData()),
+ name, false));
+ };
+
+ AddSection("debug_line_str", getOrLoadLineStrData());
+ AddSection("debug_cu_index", getOrLoadCuIndexData());
+ AddSection("debug_tu_index", getOrLoadTuIndexData());
+ if (isDwo()) {
+ AddSection("debug_info.dwo", getOrLoadDebugInfoData());
+ AddSection("debug_types.dwo", getOrLoadDebugTypesData());
+ }
+ m_llvm_context = llvm::DWARFContext::create(section_map, addr_size);
+ }
+ return *m_llvm_context;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.h
new file mode 100644
index 000000000000..87c6eb209337
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.h
@@ -0,0 +1,85 @@
+//===-- DWARFContext.h ------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFCONTEXT_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFCONTEXT_H
+
+#include "DWARFDataExtractor.h"
+#include "lldb/Core/Section.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/Support/Threading.h"
+#include <memory>
+#include <optional>
+
+namespace lldb_private::plugin {
+namespace dwarf {
+class DWARFContext {
+private:
+ SectionList *m_main_section_list;
+ SectionList *m_dwo_section_list;
+ mutable std::unique_ptr<llvm::DWARFContext> m_llvm_context;
+
+ struct SectionData {
+ llvm::once_flag flag;
+ DWARFDataExtractor data;
+ };
+
+ SectionData m_data_debug_abbrev;
+ SectionData m_data_debug_addr;
+ SectionData m_data_debug_aranges;
+ SectionData m_data_debug_cu_index;
+ SectionData m_data_debug_info;
+ SectionData m_data_debug_line;
+ SectionData m_data_debug_line_str;
+ SectionData m_data_debug_loc;
+ SectionData m_data_debug_loclists;
+ SectionData m_data_debug_macro;
+ SectionData m_data_debug_ranges;
+ SectionData m_data_debug_rnglists;
+ SectionData m_data_debug_str;
+ SectionData m_data_debug_str_offsets;
+ SectionData m_data_debug_tu_index;
+ SectionData m_data_debug_types;
+
+ const DWARFDataExtractor &
+ LoadOrGetSection(std::optional<lldb::SectionType> main_section_type,
+ std::optional<lldb::SectionType> dwo_section_type,
+ SectionData &data);
+
+ const DWARFDataExtractor &getOrLoadCuIndexData();
+ const DWARFDataExtractor &getOrLoadTuIndexData();
+
+public:
+ explicit DWARFContext(SectionList *main_section_list,
+ SectionList *dwo_section_list)
+ : m_main_section_list(main_section_list),
+ m_dwo_section_list(dwo_section_list) {}
+
+ const DWARFDataExtractor &getOrLoadAbbrevData();
+ const DWARFDataExtractor &getOrLoadAddrData();
+ const DWARFDataExtractor &getOrLoadArangesData();
+ const DWARFDataExtractor &getOrLoadDebugInfoData();
+ const DWARFDataExtractor &getOrLoadLineData();
+ const DWARFDataExtractor &getOrLoadLineStrData();
+ const DWARFDataExtractor &getOrLoadLocData();
+ const DWARFDataExtractor &getOrLoadLocListsData();
+ const DWARFDataExtractor &getOrLoadMacroData();
+ const DWARFDataExtractor &getOrLoadRangesData();
+ const DWARFDataExtractor &getOrLoadRngListsData();
+ const DWARFDataExtractor &getOrLoadStrData();
+ const DWARFDataExtractor &getOrLoadStrOffsetsData();
+ const DWARFDataExtractor &getOrLoadDebugTypesData();
+
+ bool isDwo() { return m_dwo_section_list != nullptr; }
+
+ llvm::DWARFContext &GetAsLLVM();
+};
+} // namespace dwarf
+} // namespace lldb_private::plugin
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp
new file mode 100644
index 000000000000..fb32e2adeb3f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp
@@ -0,0 +1,593 @@
+//===-- DWARFDIE.cpp ------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDIE.h"
+
+#include "DWARFASTParser.h"
+#include "DWARFDebugInfo.h"
+#include "DWARFDebugInfoEntry.h"
+#include "DWARFDeclContext.h"
+#include "DWARFUnit.h"
+#include "lldb/Symbol/Type.h"
+
+#include "llvm/ADT/iterator.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+
+using namespace lldb_private;
+using namespace lldb_private::dwarf;
+using namespace lldb_private::plugin::dwarf;
+
+namespace {
+
+/// Iterate through all DIEs elaborating (i.e. reachable by a chain of
+/// DW_AT_specification and DW_AT_abstract_origin attributes) a given DIE. For
+/// convenience, the starting die is included in the sequence as the first
+/// item.
+class ElaboratingDIEIterator
+ : public llvm::iterator_facade_base<
+ ElaboratingDIEIterator, std::input_iterator_tag, DWARFDIE,
+ std::ptrdiff_t, DWARFDIE *, DWARFDIE *> {
+
+ // The operating invariant is: top of m_worklist contains the "current" item
+ // and the rest of the list are items yet to be visited. An empty worklist
+ // means we've reached the end.
+ // Infinite recursion is prevented by maintaining a list of seen DIEs.
+ // Container sizes are optimized for the case of following DW_AT_specification
+ // and DW_AT_abstract_origin just once.
+ llvm::SmallVector<DWARFDIE, 2> m_worklist;
+ llvm::SmallSet<DWARFDebugInfoEntry *, 3> m_seen;
+
+ void Next() {
+ assert(!m_worklist.empty() && "Incrementing end iterator?");
+
+ // Pop the current item from the list.
+ DWARFDIE die = m_worklist.back();
+ m_worklist.pop_back();
+
+ // And add back any items that elaborate it.
+ for (dw_attr_t attr : {DW_AT_specification, DW_AT_abstract_origin}) {
+ if (DWARFDIE d = die.GetReferencedDIE(attr))
+ if (m_seen.insert(die.GetDIE()).second)
+ m_worklist.push_back(d);
+ }
+ }
+
+public:
+ /// An iterator starting at die d.
+ explicit ElaboratingDIEIterator(DWARFDIE d) : m_worklist(1, d) {}
+
+ /// End marker
+ ElaboratingDIEIterator() = default;
+
+ const DWARFDIE &operator*() const { return m_worklist.back(); }
+ ElaboratingDIEIterator &operator++() {
+ Next();
+ return *this;
+ }
+
+ friend bool operator==(const ElaboratingDIEIterator &a,
+ const ElaboratingDIEIterator &b) {
+ if (a.m_worklist.empty() || b.m_worklist.empty())
+ return a.m_worklist.empty() == b.m_worklist.empty();
+ return a.m_worklist.back() == b.m_worklist.back();
+ }
+};
+
+llvm::iterator_range<ElaboratingDIEIterator>
+elaborating_dies(const DWARFDIE &die) {
+ return llvm::make_range(ElaboratingDIEIterator(die),
+ ElaboratingDIEIterator());
+}
+} // namespace
+
+DWARFDIE
+DWARFDIE::GetParent() const {
+ if (IsValid())
+ return DWARFDIE(m_cu, m_die->GetParent());
+ else
+ return DWARFDIE();
+}
+
+DWARFDIE
+DWARFDIE::GetFirstChild() const {
+ if (IsValid())
+ return DWARFDIE(m_cu, m_die->GetFirstChild());
+ else
+ return DWARFDIE();
+}
+
+DWARFDIE
+DWARFDIE::GetSibling() const {
+ if (IsValid())
+ return DWARFDIE(m_cu, m_die->GetSibling());
+ else
+ return DWARFDIE();
+}
+
+DWARFDIE
+DWARFDIE::GetReferencedDIE(const dw_attr_t attr) const {
+ if (IsValid())
+ return m_die->GetAttributeValueAsReference(GetCU(), attr);
+ else
+ return {};
+}
+
+DWARFDIE
+DWARFDIE::GetDIE(dw_offset_t die_offset) const {
+ if (IsValid())
+ return m_cu->GetDIE(die_offset);
+ else
+ return DWARFDIE();
+}
+
+DWARFDIE
+DWARFDIE::GetAttributeValueAsReferenceDIE(const dw_attr_t attr) const {
+ if (IsValid()) {
+ DWARFUnit *cu = GetCU();
+ const bool check_specification_or_abstract_origin = true;
+ DWARFFormValue form_value;
+ if (m_die->GetAttributeValue(cu, attr, form_value, nullptr,
+ check_specification_or_abstract_origin))
+ return form_value.Reference();
+ }
+ return DWARFDIE();
+}
+
+DWARFDIE
+DWARFDIE::LookupDeepestBlock(lldb::addr_t address) const {
+ if (!IsValid())
+ return DWARFDIE();
+
+ DWARFDIE result;
+ bool check_children = false;
+ bool match_addr_range = false;
+ switch (Tag()) {
+ case DW_TAG_class_type:
+ case DW_TAG_namespace:
+ case DW_TAG_structure_type:
+ case DW_TAG_common_block:
+ check_children = true;
+ break;
+ case DW_TAG_compile_unit:
+ case DW_TAG_module:
+ case DW_TAG_catch_block:
+ case DW_TAG_subprogram:
+ case DW_TAG_try_block:
+ case DW_TAG_partial_unit:
+ match_addr_range = true;
+ break;
+ case DW_TAG_lexical_block:
+ case DW_TAG_inlined_subroutine:
+ check_children = true;
+ match_addr_range = true;
+ break;
+ default:
+ break;
+ }
+
+ if (match_addr_range) {
+ DWARFRangeList ranges =
+ m_die->GetAttributeAddressRanges(m_cu, /*check_hi_lo_pc=*/true);
+ if (ranges.FindEntryThatContains(address)) {
+ check_children = true;
+ switch (Tag()) {
+ default:
+ break;
+
+ case DW_TAG_inlined_subroutine: // Inlined Function
+ case DW_TAG_lexical_block: // Block { } in code
+ result = *this;
+ break;
+ }
+ } else {
+ check_children = false;
+ }
+ }
+
+ if (check_children) {
+ for (DWARFDIE child : children()) {
+ if (DWARFDIE child_result = child.LookupDeepestBlock(address))
+ return child_result;
+ }
+ }
+ return result;
+}
+
+const char *DWARFDIE::GetMangledName() const {
+ if (IsValid())
+ return m_die->GetMangledName(m_cu);
+ else
+ return nullptr;
+}
+
+const char *DWARFDIE::GetPubname() const {
+ if (IsValid())
+ return m_die->GetPubname(m_cu);
+ else
+ return nullptr;
+}
+
+// GetName
+//
+// Get value of the DW_AT_name attribute and place that value into the supplied
+// stream object. If the DIE is a NULL object "NULL" is placed into the stream,
+// and if no DW_AT_name attribute exists for the DIE then nothing is printed.
+void DWARFDIE::GetName(Stream &s) const {
+ if (!IsValid())
+ return;
+ if (GetDIE()->IsNULL()) {
+ s.PutCString("NULL");
+ return;
+ }
+ const char *name = GetDIE()->GetAttributeValueAsString(GetCU(), DW_AT_name, nullptr, true);
+ if (!name)
+ return;
+ s.PutCString(name);
+}
+
+// AppendTypeName
+//
+// Follows the type name definition down through all needed tags to end up with
+// a fully qualified type name and dump the results to the supplied stream.
+// This is used to show the name of types given a type identifier.
+void DWARFDIE::AppendTypeName(Stream &s) const {
+ if (!IsValid())
+ return;
+ if (GetDIE()->IsNULL()) {
+ s.PutCString("NULL");
+ return;
+ }
+ if (const char *name = GetPubname()) {
+ s.PutCString(name);
+ return;
+ }
+ switch (Tag()) {
+ case DW_TAG_array_type:
+ break; // print out a "[]" after printing the full type of the element
+ // below
+ case DW_TAG_base_type:
+ s.PutCString("base ");
+ break;
+ case DW_TAG_class_type:
+ s.PutCString("class ");
+ break;
+ case DW_TAG_const_type:
+ s.PutCString("const ");
+ break;
+ case DW_TAG_enumeration_type:
+ s.PutCString("enum ");
+ break;
+ case DW_TAG_file_type:
+ s.PutCString("file ");
+ break;
+ case DW_TAG_interface_type:
+ s.PutCString("interface ");
+ break;
+ case DW_TAG_packed_type:
+ s.PutCString("packed ");
+ break;
+ case DW_TAG_pointer_type:
+ break; // print out a '*' after printing the full type below
+ case DW_TAG_ptr_to_member_type:
+ break; // print out a '*' after printing the full type below
+ case DW_TAG_reference_type:
+ break; // print out a '&' after printing the full type below
+ case DW_TAG_restrict_type:
+ s.PutCString("restrict ");
+ break;
+ case DW_TAG_set_type:
+ s.PutCString("set ");
+ break;
+ case DW_TAG_shared_type:
+ s.PutCString("shared ");
+ break;
+ case DW_TAG_string_type:
+ s.PutCString("string ");
+ break;
+ case DW_TAG_structure_type:
+ s.PutCString("struct ");
+ break;
+ case DW_TAG_subrange_type:
+ s.PutCString("subrange ");
+ break;
+ case DW_TAG_subroutine_type:
+ s.PutCString("function ");
+ break;
+ case DW_TAG_thrown_type:
+ s.PutCString("thrown ");
+ break;
+ case DW_TAG_union_type:
+ s.PutCString("union ");
+ break;
+ case DW_TAG_unspecified_type:
+ s.PutCString("unspecified ");
+ break;
+ case DW_TAG_volatile_type:
+ s.PutCString("volatile ");
+ break;
+ case DW_TAG_LLVM_ptrauth_type: {
+ unsigned key = GetAttributeValueAsUnsigned(DW_AT_LLVM_ptrauth_key, 0);
+ bool isAddressDiscriminated = GetAttributeValueAsUnsigned(
+ DW_AT_LLVM_ptrauth_address_discriminated, 0);
+ unsigned extraDiscriminator =
+ GetAttributeValueAsUnsigned(DW_AT_LLVM_ptrauth_extra_discriminator, 0);
+ bool isaPointer =
+ GetAttributeValueAsUnsigned(DW_AT_LLVM_ptrauth_isa_pointer, 0);
+ bool authenticatesNullValues = GetAttributeValueAsUnsigned(
+ DW_AT_LLVM_ptrauth_authenticates_null_values, 0);
+ unsigned authenticationMode =
+ GetAttributeValueAsUnsigned(DW_AT_LLVM_ptrauth_authentication_mode, 3);
+
+ s.Printf("__ptrauth(%d, %d, 0x0%x, %d, %d, %d)", key,
+ isAddressDiscriminated, extraDiscriminator, isaPointer,
+ authenticatesNullValues, authenticationMode);
+ break;
+ }
+ default:
+ return;
+ }
+
+ // Follow the DW_AT_type if possible
+ if (DWARFDIE next_die = GetAttributeValueAsReferenceDIE(DW_AT_type))
+ next_die.AppendTypeName(s);
+
+ switch (Tag()) {
+ case DW_TAG_array_type:
+ s.PutCString("[]");
+ break;
+ case DW_TAG_pointer_type:
+ s.PutChar('*');
+ break;
+ case DW_TAG_ptr_to_member_type:
+ s.PutChar('*');
+ break;
+ case DW_TAG_reference_type:
+ s.PutChar('&');
+ break;
+ default:
+ break;
+ }
+}
+
+lldb_private::Type *DWARFDIE::ResolveType() const {
+ if (IsValid())
+ return GetDWARF()->ResolveType(*this, true);
+ else
+ return nullptr;
+}
+
+lldb_private::Type *DWARFDIE::ResolveTypeUID(const DWARFDIE &die) const {
+ if (SymbolFileDWARF *dwarf = GetDWARF())
+ return dwarf->ResolveTypeUID(die, true);
+ return nullptr;
+}
+
+static void GetDeclContextImpl(DWARFDIE die,
+ llvm::SmallSet<lldb::user_id_t, 4> &seen,
+ std::vector<CompilerContext> &context) {
+ // Stop if we hit a cycle.
+ while (die && seen.insert(die.GetID()).second) {
+ // Handle outline member function DIEs by following the specification.
+ if (DWARFDIE spec = die.GetReferencedDIE(DW_AT_specification)) {
+ die = spec;
+ continue;
+ }
+ // To find the name of a type in a type unit, we must follow the signature.
+ if (DWARFDIE spec = die.GetReferencedDIE(DW_AT_signature)) {
+ die = spec;
+ continue;
+ }
+
+ // Add this DIE's contribution at the end of the chain.
+ auto push_ctx = [&](CompilerContextKind kind, llvm::StringRef name) {
+ context.push_back({kind, ConstString(name)});
+ };
+ switch (die.Tag()) {
+ case DW_TAG_module:
+ push_ctx(CompilerContextKind::Module, die.GetName());
+ break;
+ case DW_TAG_namespace:
+ push_ctx(CompilerContextKind::Namespace, die.GetName());
+ break;
+ case DW_TAG_class_type:
+ case DW_TAG_structure_type:
+ push_ctx(CompilerContextKind::ClassOrStruct, die.GetName());
+ break;
+ case DW_TAG_union_type:
+ push_ctx(CompilerContextKind::Union, die.GetName());
+ break;
+ case DW_TAG_enumeration_type:
+ push_ctx(CompilerContextKind::Enum, die.GetName());
+ break;
+ case DW_TAG_subprogram:
+ push_ctx(CompilerContextKind::Function, die.GetName());
+ break;
+ case DW_TAG_variable:
+ push_ctx(CompilerContextKind::Variable, die.GetPubname());
+ break;
+ case DW_TAG_typedef:
+ push_ctx(CompilerContextKind::Typedef, die.GetName());
+ break;
+ default:
+ break;
+ }
+ // Now process the parent.
+ die = die.GetParent();
+ }
+}
+
+std::vector<CompilerContext> DWARFDIE::GetDeclContext() const {
+ llvm::SmallSet<lldb::user_id_t, 4> seen;
+ std::vector<CompilerContext> context;
+ GetDeclContextImpl(*this, seen, context);
+ std::reverse(context.begin(), context.end());
+ return context;
+}
+
+static void GetTypeLookupContextImpl(DWARFDIE die,
+ llvm::SmallSet<lldb::user_id_t, 4> &seen,
+ std::vector<CompilerContext> &context) {
+ // Stop if we hit a cycle.
+ while (die && seen.insert(die.GetID()).second) {
+ // To find the name of a type in a type unit, we must follow the signature.
+ if (DWARFDIE spec = die.GetReferencedDIE(DW_AT_signature)) {
+ die = spec;
+ continue;
+ }
+
+ // If there is no name, then there is no need to look anything up for this
+ // DIE.
+ const char *name = die.GetName();
+ if (!name || !name[0])
+ return;
+
+ // Add this DIE's contribution at the end of the chain.
+ auto push_ctx = [&](CompilerContextKind kind, llvm::StringRef name) {
+ context.push_back({kind, ConstString(name)});
+ };
+ switch (die.Tag()) {
+ case DW_TAG_namespace:
+ push_ctx(CompilerContextKind::Namespace, die.GetName());
+ break;
+ case DW_TAG_class_type:
+ case DW_TAG_structure_type:
+ push_ctx(CompilerContextKind::ClassOrStruct, die.GetName());
+ break;
+ case DW_TAG_union_type:
+ push_ctx(CompilerContextKind::Union, die.GetName());
+ break;
+ case DW_TAG_enumeration_type:
+ push_ctx(CompilerContextKind::Enum, die.GetName());
+ break;
+ case DW_TAG_variable:
+ push_ctx(CompilerContextKind::Variable, die.GetPubname());
+ break;
+ case DW_TAG_typedef:
+ push_ctx(CompilerContextKind::Typedef, die.GetName());
+ break;
+ case DW_TAG_base_type:
+ push_ctx(CompilerContextKind::Builtin, name);
+ break;
+ // If any of the tags below appear in the parent chain, stop the decl
+ // context and return. Prior to these being in here, if a type existed in a
+ // namespace "a" like "a::my_struct", but we also have a function in that
+ // same namespace "a" which contained a type named "my_struct", both would
+ // return "a::my_struct" as the declaration context since the
+ // DW_TAG_subprogram would be skipped and its parent would be found.
+ case DW_TAG_compile_unit:
+ case DW_TAG_type_unit:
+ case DW_TAG_subprogram:
+ case DW_TAG_lexical_block:
+ case DW_TAG_inlined_subroutine:
+ return;
+ default:
+ break;
+ }
+ // Now process the parent.
+ die = die.GetParent();
+ }
+}
+
+std::vector<CompilerContext> DWARFDIE::GetTypeLookupContext() const {
+ llvm::SmallSet<lldb::user_id_t, 4> seen;
+ std::vector<CompilerContext> context;
+ GetTypeLookupContextImpl(*this, seen, context);
+ std::reverse(context.begin(), context.end());
+ return context;
+}
+
+static DWARFDeclContext GetDWARFDeclContextImpl(DWARFDIE die) {
+ DWARFDeclContext dwarf_decl_ctx;
+ while (die) {
+ const dw_tag_t tag = die.Tag();
+ if (tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit)
+ break;
+ dwarf_decl_ctx.AppendDeclContext(tag, die.GetName());
+ DWARFDIE parent_decl_ctx_die = die.GetParentDeclContextDIE();
+ if (parent_decl_ctx_die == die)
+ break;
+ die = parent_decl_ctx_die;
+ }
+ return dwarf_decl_ctx;
+}
+
+DWARFDeclContext DWARFDIE::GetDWARFDeclContext() const {
+ return GetDWARFDeclContextImpl(*this);
+}
+
+static DWARFDIE GetParentDeclContextDIEImpl(DWARFDIE die) {
+ DWARFDIE orig_die = die;
+ while (die) {
+ // If this is the original DIE that we are searching for a declaration for,
+ // then don't look in the cache as we don't want our own decl context to be
+ // our decl context...
+ if (die != orig_die) {
+ switch (die.Tag()) {
+ case DW_TAG_compile_unit:
+ case DW_TAG_partial_unit:
+ case DW_TAG_namespace:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_class_type:
+ return die;
+
+ default:
+ break;
+ }
+ }
+
+ if (DWARFDIE spec_die = die.GetReferencedDIE(DW_AT_specification)) {
+ if (DWARFDIE decl_ctx_die = spec_die.GetParentDeclContextDIE())
+ return decl_ctx_die;
+ }
+
+ if (DWARFDIE abs_die = die.GetReferencedDIE(DW_AT_abstract_origin)) {
+ if (DWARFDIE decl_ctx_die = abs_die.GetParentDeclContextDIE())
+ return decl_ctx_die;
+ }
+
+ die = die.GetParent();
+ }
+ return DWARFDIE();
+}
+
+DWARFDIE
+DWARFDIE::GetParentDeclContextDIE() const {
+ return GetParentDeclContextDIEImpl(*this);
+}
+
+bool DWARFDIE::IsStructUnionOrClass() const {
+ const dw_tag_t tag = Tag();
+ return tag == DW_TAG_class_type || tag == DW_TAG_structure_type ||
+ tag == DW_TAG_union_type;
+}
+
+bool DWARFDIE::IsMethod() const {
+ for (DWARFDIE d : elaborating_dies(*this))
+ if (d.GetParent().IsStructUnionOrClass())
+ return true;
+ return false;
+}
+
+bool DWARFDIE::GetDIENamesAndRanges(
+ const char *&name, const char *&mangled, DWARFRangeList &ranges,
+ std::optional<int> &decl_file, std::optional<int> &decl_line,
+ std::optional<int> &decl_column, std::optional<int> &call_file,
+ std::optional<int> &call_line, std::optional<int> &call_column,
+ lldb_private::DWARFExpressionList *frame_base) const {
+ if (IsValid()) {
+ return m_die->GetDIENamesAndRanges(
+ GetCU(), name, mangled, ranges, decl_file, decl_line, decl_column,
+ call_file, call_line, call_column, frame_base);
+ } else
+ return false;
+}
+
+llvm::iterator_range<DWARFDIE::child_iterator> DWARFDIE::children() const {
+ return llvm::make_range(child_iterator(*this), child_iterator());
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h
new file mode 100644
index 000000000000..e1318953a384
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h
@@ -0,0 +1,145 @@
+//===-- DWARFDIE.h ----------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDIE_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDIE_H
+
+#include "DWARFBaseDIE.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/iterator_range.h"
+
+namespace lldb_private::plugin {
+namespace dwarf {
+class DWARFDIE : public DWARFBaseDIE {
+public:
+ class child_iterator;
+ using DWARFBaseDIE::DWARFBaseDIE;
+
+ // Tests
+ bool IsStructUnionOrClass() const;
+
+ bool IsMethod() const;
+
+ // Accessors
+
+ // Accessing information about a DIE
+ const char *GetMangledName() const;
+
+ const char *GetPubname() const;
+
+ using DWARFBaseDIE::GetName;
+ void GetName(Stream &s) const;
+
+ void AppendTypeName(Stream &s) const;
+
+ Type *ResolveType() const;
+
+ // Resolve a type by UID using this DIE's DWARF file
+ Type *ResolveTypeUID(const DWARFDIE &die) const;
+
+ // Functions for obtaining DIE relations and references
+
+ DWARFDIE
+ GetParent() const;
+
+ DWARFDIE
+ GetFirstChild() const;
+
+ DWARFDIE
+ GetSibling() const;
+
+ DWARFDIE
+ GetReferencedDIE(const dw_attr_t attr) const;
+
+ // Get a another DIE from the same DWARF file as this DIE. This will
+ // check the current DIE's compile unit first to see if "die_offset" is
+ // in the same compile unit, and fall back to checking the DWARF file.
+ DWARFDIE
+ GetDIE(dw_offset_t die_offset) const;
+ using DWARFBaseDIE::GetDIE;
+
+ DWARFDIE
+ LookupDeepestBlock(lldb::addr_t file_addr) const;
+
+ DWARFDIE
+ GetParentDeclContextDIE() const;
+
+ /// Return this DIE's decl context as it is needed to look up types
+ /// in Clang modules. This context will include any modules or functions that
+ /// the type is declared in so an exact module match can be efficiently made.
+ std::vector<CompilerContext> GetDeclContext() const;
+
+ /// Get a context to a type so it can be looked up.
+ ///
+ /// This function uses the current DIE to fill in a CompilerContext array
+ /// that is suitable for type lookup for comparison to a TypeQuery's compiler
+ /// context (TypeQuery::GetContextRef()). If this DIE represents a named type,
+ /// it should fill out the compiler context with the type itself as the last
+ /// entry. The declaration context should be above the type and stop at an
+ /// appropriate time, like either the translation unit or at a function
+ /// context. This is designed to allow users to efficiently look for types
+ /// using a full or partial CompilerContext array.
+ std::vector<CompilerContext> GetTypeLookupContext() const;
+
+ DWARFDeclContext GetDWARFDeclContext() const;
+
+ // Getting attribute values from the DIE.
+ //
+ // GetAttributeValueAsXXX() functions should only be used if you are
+ // looking for one or two attributes on a DIE. If you are trying to
+ // parse all attributes, use GetAttributes (...) instead
+ DWARFDIE
+ GetAttributeValueAsReferenceDIE(const dw_attr_t attr) const;
+
+ bool GetDIENamesAndRanges(
+ const char *&name, const char *&mangled, DWARFRangeList &ranges,
+ std::optional<int> &decl_file, std::optional<int> &decl_line,
+ std::optional<int> &decl_column, std::optional<int> &call_file,
+ std::optional<int> &call_line, std::optional<int> &call_column,
+ DWARFExpressionList *frame_base) const;
+
+ /// The range of all the children of this DIE.
+ llvm::iterator_range<child_iterator> children() const;
+};
+
+class DWARFDIE::child_iterator
+ : public llvm::iterator_facade_base<DWARFDIE::child_iterator,
+ std::forward_iterator_tag, DWARFDIE> {
+ /// The current child or an invalid DWARFDie.
+ DWARFDIE m_die;
+
+public:
+ child_iterator() = default;
+ child_iterator(const DWARFDIE &parent) : m_die(parent.GetFirstChild()) {}
+ bool operator==(const child_iterator &it) const {
+ // DWARFDIE's operator== differentiates between an invalid DWARFDIE that
+ // has a CU but no DIE and one that has neither CU nor DIE. The 'end'
+ // iterator could be default constructed, so explicitly allow
+ // (CU, (DIE)nullptr) == (nullptr, nullptr) -> true
+ if (!m_die.IsValid() && !it.m_die.IsValid())
+ return true;
+ return m_die == it.m_die;
+ }
+ const DWARFDIE &operator*() const {
+ assert(m_die.IsValid() && "Derefencing invalid iterator?");
+ return m_die;
+ }
+ DWARFDIE &operator*() {
+ assert(m_die.IsValid() && "Derefencing invalid iterator?");
+ return m_die;
+ }
+ child_iterator &operator++() {
+ assert(m_die.IsValid() && "Incrementing invalid iterator?");
+ m_die = m_die.GetSibling();
+ return *this;
+ }
+};
+} // namespace dwarf
+} // namespace lldb_private::plugin
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDIE_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.cpp
new file mode 100644
index 000000000000..c5876502b8f2
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.cpp
@@ -0,0 +1,34 @@
+//===-- DWARFDataExtractor.cpp --------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDataExtractor.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace lldb_private {
+
+uint64_t
+DWARFDataExtractor::GetDWARFInitialLength(lldb::offset_t *offset_ptr) const {
+ return GetU32(offset_ptr);
+}
+
+dw_offset_t
+DWARFDataExtractor::GetDWARFOffset(lldb::offset_t *offset_ptr) const {
+ return GetMaxU64(offset_ptr, GetDWARFSizeOfOffset());
+}
+
+llvm::DWARFDataExtractor DWARFDataExtractor::GetAsLLVMDWARF() const {
+ return llvm::DWARFDataExtractor(llvm::ArrayRef(GetDataStart(), GetByteSize()),
+ GetByteOrder() == lldb::eByteOrderLittle,
+ GetAddressByteSize());
+}
+llvm::DataExtractor DWARFDataExtractor::GetAsLLVM() const {
+ return llvm::DataExtractor(llvm::ArrayRef(GetDataStart(), GetByteSize()),
+ GetByteOrder() == lldb::eByteOrderLittle,
+ GetAddressByteSize());
+}
+} // namespace lldb_private
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h
new file mode 100644
index 000000000000..41b8e9ad0217
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h
@@ -0,0 +1,38 @@
+//===-- DWARFDataExtractor.h ------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDATAEXTRACTOR_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDATAEXTRACTOR_H
+
+#include "lldb/Core/dwarf.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
+
+namespace lldb_private {
+
+class DWARFDataExtractor : public DataExtractor {
+public:
+ DWARFDataExtractor() = default;
+
+ DWARFDataExtractor(const DWARFDataExtractor &data, lldb::offset_t offset,
+ lldb::offset_t length)
+ : DataExtractor(data, offset, length) {}
+
+ uint64_t GetDWARFInitialLength(lldb::offset_t *offset_ptr) const;
+
+ dw_offset_t GetDWARFOffset(lldb::offset_t *offset_ptr) const;
+
+ size_t GetDWARFSizeofInitialLength() const { return 4; }
+ size_t GetDWARFSizeOfOffset() const { return 4; }
+
+ llvm::DWARFDataExtractor GetAsLLVMDWARF() const;
+ llvm::DataExtractor GetAsLLVM() const;
+};
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDATAEXTRACTOR_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp
new file mode 100644
index 000000000000..8461b94abca6
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp
@@ -0,0 +1,176 @@
+//===-- DWARFDebugArangeSet.cpp -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugArangeSet.h"
+#include "DWARFDataExtractor.h"
+#include "LogChannelDWARF.h"
+#include "llvm/Object/Error.h"
+#include <cassert>
+
+using namespace lldb_private;
+using namespace lldb_private::plugin::dwarf;
+
+DWARFDebugArangeSet::DWARFDebugArangeSet()
+ : m_offset(DW_INVALID_OFFSET), m_next_offset(DW_INVALID_OFFSET) {}
+
+void DWARFDebugArangeSet::Clear() {
+ m_offset = DW_INVALID_OFFSET;
+ m_next_offset = DW_INVALID_OFFSET;
+ m_header.length = 0;
+ m_header.version = 0;
+ m_header.cu_offset = 0;
+ m_header.addr_size = 0;
+ m_header.seg_size = 0;
+ m_arange_descriptors.clear();
+}
+
+llvm::Error DWARFDebugArangeSet::extract(const DWARFDataExtractor &data,
+ lldb::offset_t *offset_ptr) {
+ assert(data.ValidOffset(*offset_ptr));
+
+ m_arange_descriptors.clear();
+ m_offset = *offset_ptr;
+
+ // 7.20 Address Range Table
+ //
+ // Each set of entries in the table of address ranges contained in the
+ // .debug_aranges section begins with a header consisting of: a 4-byte
+ // length containing the length of the set of entries for this compilation
+ // unit, not including the length field itself; a 2-byte version identifier
+ // containing the value 2 for DWARF Version 2; a 4-byte offset into
+ // the.debug_infosection; a 1-byte unsigned integer containing the size in
+ // bytes of an address (or the offset portion of an address for segmented
+ // addressing) on the target system; and a 1-byte unsigned integer
+ // containing the size in bytes of a segment descriptor on the target
+ // system. This header is followed by a series of tuples. Each tuple
+ // consists of an address and a length, each in the size appropriate for an
+ // address on the target architecture.
+ m_header.length = data.GetDWARFInitialLength(offset_ptr);
+ // The length could be 4 bytes or 12 bytes, so use the current offset to
+ // determine the next offset correctly.
+ if (m_header.length > 0)
+ m_next_offset = *offset_ptr + m_header.length;
+ else
+ m_next_offset = DW_INVALID_OFFSET;
+ m_header.version = data.GetU16(offset_ptr);
+ m_header.cu_offset = data.GetDWARFOffset(offset_ptr);
+ m_header.addr_size = data.GetU8(offset_ptr);
+ m_header.seg_size = data.GetU8(offset_ptr);
+
+ // Try to avoid reading invalid arange sets by making sure:
+ // 1 - the version looks good
+ // 2 - the address byte size looks plausible
+ // 3 - the length seems to make sense
+ // 4 - size looks plausible
+ // 5 - the arange tuples do not contain a segment field
+ if (m_header.version < 2 || m_header.version > 5)
+ return llvm::make_error<llvm::object::GenericBinaryError>(
+ "Invalid arange header version");
+
+ if (m_header.addr_size != 4 && m_header.addr_size != 8)
+ return llvm::make_error<llvm::object::GenericBinaryError>(
+ "Invalid arange header address size");
+
+ if (m_header.length == 0)
+ return llvm::make_error<llvm::object::GenericBinaryError>(
+ "Invalid arange header length");
+
+ if (!data.ValidOffset(m_offset + sizeof(m_header.length) + m_header.length -
+ 1))
+ return llvm::make_error<llvm::object::GenericBinaryError>(
+ "Invalid arange header length");
+
+ if (m_header.seg_size)
+ return llvm::make_error<llvm::object::GenericBinaryError>(
+ "segmented arange entries are not supported");
+
+ // The first tuple following the header in each set begins at an offset
+ // that is a multiple of the size of a single tuple (that is, twice the
+ // size of an address). The header is padded, if necessary, to the
+ // appropriate boundary.
+ const uint32_t header_size = *offset_ptr - m_offset;
+ const uint32_t tuple_size = m_header.addr_size << 1;
+ uint32_t first_tuple_offset = 0;
+ while (first_tuple_offset < header_size)
+ first_tuple_offset += tuple_size;
+
+ *offset_ptr = m_offset + first_tuple_offset;
+
+ Descriptor arangeDescriptor;
+
+ static_assert(sizeof(arangeDescriptor.address) ==
+ sizeof(arangeDescriptor.length),
+ "DWARFDebugArangeSet::Descriptor.address and "
+ "DWARFDebugArangeSet::Descriptor.length must have same size");
+
+ const lldb::offset_t next_offset = GetNextOffset();
+ assert(next_offset != DW_INVALID_OFFSET);
+ uint32_t num_terminators = 0;
+ bool last_was_terminator = false;
+ while (*offset_ptr < next_offset) {
+ arangeDescriptor.address = data.GetMaxU64(offset_ptr, m_header.addr_size);
+ arangeDescriptor.length = data.GetMaxU64(offset_ptr, m_header.addr_size);
+
+ // Each set of tuples is terminated by a 0 for the address and 0 for
+ // the length. Some linkers can emit .debug_aranges with multiple
+ // terminator pair entries that are still withing the length of the
+ // DWARFDebugArangeSet. We want to be sure to parse all entries for
+ // this DWARFDebugArangeSet so that we don't stop parsing early and end up
+ // treating addresses as a header of the next DWARFDebugArangeSet. We also
+ // need to make sure we parse all valid address pairs so we don't omit them
+ // from the aranges result, so we can't stop at the first terminator entry
+ // we find.
+ if (arangeDescriptor.address == 0 && arangeDescriptor.length == 0) {
+ ++num_terminators;
+ last_was_terminator = true;
+ } else {
+ last_was_terminator = false;
+ // Only add .debug_aranges address entries that have a non zero size.
+ // Some linkers will zero out the length field for some .debug_aranges
+ // entries if they were stripped. We also could watch out for multiple
+ // entries at address zero and remove those as well.
+ if (arangeDescriptor.length > 0)
+ m_arange_descriptors.push_back(arangeDescriptor);
+ }
+ }
+ if (num_terminators > 1) {
+ Log *log = GetLog(DWARFLog::DebugInfo);
+ LLDB_LOG(log,
+ "warning: DWARFDebugArangeSet at %#" PRIx64 " contains %u "
+ "terminator entries",
+ m_offset, num_terminators);
+ }
+ if (last_was_terminator)
+ return llvm::ErrorSuccess();
+
+ return llvm::make_error<llvm::object::GenericBinaryError>(
+ "arange descriptors not terminated by null entry");
+}
+
+class DescriptorContainsAddress {
+public:
+ DescriptorContainsAddress(dw_addr_t address) : m_address(address) {}
+ bool operator()(const DWARFDebugArangeSet::Descriptor &desc) const {
+ return (m_address >= desc.address) &&
+ (m_address < (desc.address + desc.length));
+ }
+
+private:
+ const dw_addr_t m_address;
+};
+
+dw_offset_t DWARFDebugArangeSet::FindAddress(dw_addr_t address) const {
+ DescriptorConstIter end = m_arange_descriptors.end();
+ DescriptorConstIter pos =
+ std::find_if(m_arange_descriptors.begin(), end, // Range
+ DescriptorContainsAddress(address)); // Predicate
+ if (pos != end)
+ return m_header.cu_offset;
+
+ return DW_INVALID_OFFSET;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h
new file mode 100644
index 000000000000..ecdbe953f58b
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h
@@ -0,0 +1,70 @@
+//===-- DWARFDebugArangeSet.h -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGARANGESET_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGARANGESET_H
+
+#include "lldb/Core/dwarf.h"
+#include <cstdint>
+#include <vector>
+
+namespace lldb_private::plugin {
+namespace dwarf {
+class DWARFDebugArangeSet {
+public:
+ struct Header {
+ /// The total length of the entries for that set, not including the length
+ /// field itself.
+ uint32_t length = 0;
+ /// The DWARF version number.
+ uint16_t version = 0;
+ /// The offset from the beginning of the .debug_info section of the
+ /// compilation unit entry referenced by the table.
+ uint32_t cu_offset = 0;
+ /// The size in bytes of an address on the target architecture. For
+ /// segmented addressing, this is the size of the offset portion of the
+ /// address.
+ uint8_t addr_size = 0;
+ /// The size in bytes of a segment descriptor on the target architecture.
+ /// If the target system uses a flat address space, this value is 0.
+ uint8_t seg_size = 0;
+ };
+
+ struct Descriptor {
+ dw_addr_t address;
+ dw_addr_t length;
+ dw_addr_t end_address() const { return address + length; }
+ };
+
+ DWARFDebugArangeSet();
+ void Clear();
+ void SetOffset(uint32_t offset) { m_offset = offset; }
+ llvm::Error extract(const DWARFDataExtractor &data,
+ lldb::offset_t *offset_ptr);
+ dw_offset_t FindAddress(dw_addr_t address) const;
+ size_t NumDescriptors() const { return m_arange_descriptors.size(); }
+ const Header &GetHeader() const { return m_header; }
+ dw_offset_t GetNextOffset() const { return m_next_offset; }
+ const Descriptor &GetDescriptorRef(uint32_t i) const {
+ return m_arange_descriptors[i];
+ }
+
+protected:
+ typedef std::vector<Descriptor> DescriptorColl;
+ typedef DescriptorColl::iterator DescriptorIter;
+ typedef DescriptorColl::const_iterator DescriptorConstIter;
+
+ dw_offset_t m_offset;
+ dw_offset_t m_next_offset;
+ Header m_header;
+ DescriptorColl m_arange_descriptors;
+};
+} // namespace dwarf
+} // namespace lldb_private::plugin
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGARANGESET_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp
new file mode 100644
index 000000000000..f383261e8a5f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp
@@ -0,0 +1,104 @@
+//===-- DWARFDebugAranges.cpp ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugAranges.h"
+#include "DWARFDebugArangeSet.h"
+#include "DWARFUnit.h"
+#include "LogChannelDWARF.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Timer.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::plugin::dwarf;
+
+// Constructor
+DWARFDebugAranges::DWARFDebugAranges() : m_aranges() {}
+
+// CountArangeDescriptors
+class CountArangeDescriptors {
+public:
+ CountArangeDescriptors(uint32_t &count_ref) : count(count_ref) {
+ // printf("constructor CountArangeDescriptors()\n");
+ }
+ void operator()(const DWARFDebugArangeSet &set) {
+ count += set.NumDescriptors();
+ }
+ uint32_t &count;
+};
+
+// Extract
+void DWARFDebugAranges::extract(const DWARFDataExtractor &debug_aranges_data) {
+ lldb::offset_t offset = 0;
+
+ DWARFDebugArangeSet set;
+ Range range;
+ while (debug_aranges_data.ValidOffset(offset)) {
+ const lldb::offset_t set_offset = offset;
+ if (llvm::Error error = set.extract(debug_aranges_data, &offset)) {
+ Log *log = GetLog(DWARFLog::DebugInfo);
+ LLDB_LOG_ERROR(log, std::move(error),
+ "DWARFDebugAranges::extract failed to extract "
+ ".debug_aranges set at offset {1:x}: {0}",
+ set_offset);
+ } else {
+ const uint32_t num_descriptors = set.NumDescriptors();
+ if (num_descriptors > 0) {
+ const dw_offset_t cu_offset = set.GetHeader().cu_offset;
+
+ for (uint32_t i = 0; i < num_descriptors; ++i) {
+ const DWARFDebugArangeSet::Descriptor &descriptor =
+ set.GetDescriptorRef(i);
+ m_aranges.Append(RangeToDIE::Entry(descriptor.address,
+ descriptor.length, cu_offset));
+ }
+ }
+ }
+ // Always use the previous DWARFDebugArangeSet's information to calculate
+ // the offset of the next DWARFDebugArangeSet in case we entouncter an
+ // error in the current DWARFDebugArangeSet and our offset position is
+ // still in the middle of the data. If we do this, we can parse all valid
+ // DWARFDebugArangeSet objects without returning invalid errors.
+ offset = set.GetNextOffset();
+ set.Clear();
+ }
+}
+
+void DWARFDebugAranges::Dump(Log *log) const {
+ if (log == nullptr)
+ return;
+
+ const size_t num_entries = m_aranges.GetSize();
+ for (size_t i = 0; i < num_entries; ++i) {
+ const RangeToDIE::Entry *entry = m_aranges.GetEntryAtIndex(i);
+ if (entry)
+ LLDB_LOG(log, "{0:x8}: [{1:x16} - {2:x16})", entry->data,
+ entry->GetRangeBase(), entry->GetRangeEnd());
+ }
+}
+
+void DWARFDebugAranges::AppendRange(dw_offset_t offset, dw_addr_t low_pc,
+ dw_addr_t high_pc) {
+ if (high_pc > low_pc)
+ m_aranges.Append(RangeToDIE::Entry(low_pc, high_pc - low_pc, offset));
+}
+
+void DWARFDebugAranges::Sort(bool minimize) {
+ LLDB_SCOPED_TIMER();
+
+ m_aranges.Sort();
+ m_aranges.CombineConsecutiveEntriesWithEqualData();
+}
+
+// FindAddress
+dw_offset_t DWARFDebugAranges::FindAddress(dw_addr_t address) const {
+ const RangeToDIE::Entry *entry = m_aranges.FindEntryThatContains(address);
+ if (entry)
+ return entry->data;
+ return DW_INVALID_OFFSET;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h
new file mode 100644
index 000000000000..99e2108b85c6
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h
@@ -0,0 +1,57 @@
+//===-- DWARFDebugAranges.h -------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGARANGES_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGARANGES_H
+
+#include "lldb/Core/dwarf.h"
+#include "lldb/Utility/RangeMap.h"
+#include "llvm/Support/Error.h"
+
+namespace lldb_private::plugin {
+namespace dwarf {
+class DWARFDebugAranges {
+protected:
+ typedef RangeDataVector<dw_addr_t, uint32_t, dw_offset_t> RangeToDIE;
+
+public:
+ typedef RangeToDIE::Entry Range;
+ typedef std::vector<RangeToDIE::Entry> RangeColl;
+
+ DWARFDebugAranges();
+
+ void Clear() { m_aranges.Clear(); }
+
+ void extract(const DWARFDataExtractor &debug_aranges_data);
+
+ // Use append range multiple times and then call sort
+ void AppendRange(dw_offset_t cu_offset, dw_addr_t low_pc, dw_addr_t high_pc);
+
+ void Sort(bool minimize);
+
+ void Dump(Log *log) const;
+
+ dw_offset_t FindAddress(dw_addr_t address) const;
+
+ bool IsEmpty() const { return m_aranges.IsEmpty(); }
+ size_t GetNumRanges() const { return m_aranges.GetSize(); }
+
+ dw_offset_t OffsetAtIndex(uint32_t idx) const {
+ const Range *range = m_aranges.GetEntryAtIndex(idx);
+ if (range)
+ return range->data;
+ return DW_INVALID_OFFSET;
+ }
+
+protected:
+ RangeToDIE m_aranges;
+};
+} // namespace dwarf
+} // namespace lldb_private::plugin
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGARANGES_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
new file mode 100644
index 000000000000..f7df38d24019
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
@@ -0,0 +1,260 @@
+//===-- DWARFDebugInfo.cpp ------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolFileDWARF.h"
+
+#include <algorithm>
+#include <set>
+
+#include "lldb/Host/PosixApi.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/Stream.h"
+#include "llvm/Support/Casting.h"
+
+#include "DWARFCompileUnit.h"
+#include "DWARFContext.h"
+#include "DWARFDebugAranges.h"
+#include "DWARFDebugInfo.h"
+#include "DWARFDebugInfoEntry.h"
+#include "DWARFFormValue.h"
+#include "DWARFTypeUnit.h"
+#include "LogChannelDWARF.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::plugin::dwarf;
+
+// Constructor
+DWARFDebugInfo::DWARFDebugInfo(SymbolFileDWARF &dwarf, DWARFContext &context)
+ : m_dwarf(dwarf), m_context(context), m_units(), m_cu_aranges_up() {}
+
+const DWARFDebugAranges &DWARFDebugInfo::GetCompileUnitAranges() {
+ if (m_cu_aranges_up)
+ return *m_cu_aranges_up;
+
+ m_cu_aranges_up = std::make_unique<DWARFDebugAranges>();
+ const DWARFDataExtractor &debug_aranges_data =
+ m_context.getOrLoadArangesData();
+
+ // Extract what we can from the .debug_aranges first.
+ m_cu_aranges_up->extract(debug_aranges_data);
+
+ // Make a list of all CUs represented by the .debug_aranges data.
+ std::set<dw_offset_t> cus_with_data;
+ for (size_t n = 0; n < m_cu_aranges_up->GetNumRanges(); n++) {
+ dw_offset_t offset = m_cu_aranges_up->OffsetAtIndex(n);
+ if (offset != DW_INVALID_OFFSET)
+ cus_with_data.insert(offset);
+ }
+
+ // Manually build arange data for everything that wasn't in .debug_aranges.
+ // The .debug_aranges accelerator is not guaranteed to be complete.
+ // Tools such as dsymutil can provide stronger guarantees than required by the
+ // standard. Without that guarantee, we have to iterate over every CU in the
+ // .debug_info and make sure there's a corresponding entry in the table and if
+ // not, add one for every subprogram.
+ ObjectFile *OF = m_dwarf.GetObjectFile();
+ if (!OF || !OF->CanTrustAddressRanges()) {
+ const size_t num_units = GetNumUnits();
+ for (size_t idx = 0; idx < num_units; ++idx) {
+ DWARFUnit *cu = GetUnitAtIndex(idx);
+
+ dw_offset_t offset = cu->GetOffset();
+ if (cus_with_data.find(offset) == cus_with_data.end())
+ cu->BuildAddressRangeTable(m_cu_aranges_up.get());
+ }
+ }
+
+ const bool minimize = true;
+ m_cu_aranges_up->Sort(minimize);
+ return *m_cu_aranges_up;
+}
+
+void DWARFDebugInfo::ParseUnitsFor(DIERef::Section section) {
+ DWARFDataExtractor data = section == DIERef::Section::DebugTypes
+ ? m_context.getOrLoadDebugTypesData()
+ : m_context.getOrLoadDebugInfoData();
+ lldb::offset_t offset = 0;
+ while (data.ValidOffset(offset)) {
+ const lldb::offset_t unit_header_offset = offset;
+ llvm::Expected<DWARFUnitSP> expected_unit_sp =
+ DWARFUnit::extract(m_dwarf, m_units.size(), data, section, &offset);
+
+ if (!expected_unit_sp) {
+ Log *log = GetLog(DWARFLog::DebugInfo);
+ if (log)
+ LLDB_LOG(log, "Unable to extract DWARFUnitHeader at {0:x}: {1}",
+ unit_header_offset,
+ llvm::toString(expected_unit_sp.takeError()));
+ else
+ llvm::consumeError(expected_unit_sp.takeError());
+ return;
+ }
+
+ DWARFUnitSP unit_sp = *expected_unit_sp;
+
+ // If it didn't return an error, then it should be returning a valid Unit.
+ assert((bool)unit_sp);
+
+ // Keep a map of DWO ID back to the skeleton units. Sometimes accelerator
+ // table lookups can cause the DWO files to be accessed before the skeleton
+ // compile unit is parsed, so we keep a map to allow us to match up the DWO
+ // file to the back to the skeleton compile units.
+ if (unit_sp->GetUnitType() == lldb_private::dwarf::DW_UT_skeleton) {
+ if (std::optional<uint64_t> unit_dwo_id = unit_sp->GetHeaderDWOId())
+ m_dwarf5_dwo_id_to_skeleton_unit[*unit_dwo_id] = unit_sp.get();
+ }
+
+ m_units.push_back(unit_sp);
+ offset = unit_sp->GetNextUnitOffset();
+
+ if (auto *type_unit = llvm::dyn_cast<DWARFTypeUnit>(unit_sp.get())) {
+ m_type_hash_to_unit_index.emplace_back(type_unit->GetTypeHash(),
+ unit_sp->GetID());
+ }
+ }
+}
+
+DWARFUnit *DWARFDebugInfo::GetSkeletonUnit(DWARFUnit *dwo_unit) {
+ // If this isn't a DWO unit, don't try and find the skeleton unit.
+ if (!dwo_unit->IsDWOUnit())
+ return nullptr;
+
+ auto dwo_id = dwo_unit->GetDWOId();
+ if (!dwo_id.has_value())
+ return nullptr;
+
+ // Parse the unit headers so that m_dwarf5_dwo_id_to_skeleton_unit is filled
+ // in with all of the DWARF5 skeleton compile units DWO IDs since it is easy
+ // to access the DWO IDs in the DWARFUnitHeader for each DWARFUnit.
+ ParseUnitHeadersIfNeeded();
+
+ // Find the value in our cache and return it we we find it. This cache may
+ // only contain DWARF5 units.
+ auto iter = m_dwarf5_dwo_id_to_skeleton_unit.find(*dwo_id);
+ if (iter != m_dwarf5_dwo_id_to_skeleton_unit.end())
+ return iter->second;
+
+ // DWARF5 unit headers have the DWO ID and should have already been in the map
+ // so if it wasn't found in the above find() call, then we didn't find it and
+ // don't need to do the more expensive DWARF4 search.
+ if (dwo_unit->GetVersion() >= 5)
+ return nullptr;
+
+ // Parse all DWO IDs from all DWARF4 and earlier compile units that have DWO
+ // IDs. It is more expensive to get the DWO IDs from DWARF4 compile units as
+ // we need to parse the unit DIE and extract the DW_AT_dwo_id or
+ // DW_AT_GNU_dwo_id attribute values, so do this only if we didn't find our
+ // match above search and only for DWARF4 and earlier compile units.
+ llvm::call_once(m_dwarf4_dwo_id_to_skeleton_unit_once_flag, [this]() {
+ for (uint32_t i = 0, num = GetNumUnits(); i < num; ++i) {
+ if (DWARFUnit *unit = GetUnitAtIndex(i)) {
+ if (unit->GetVersion() < 5) {
+ if (std::optional<uint64_t> unit_dwo_id = unit->GetDWOId())
+ m_dwarf4_dwo_id_to_skeleton_unit[*unit_dwo_id] = unit;
+ }
+ }
+ }
+ });
+
+ // Search the DWARF4 DWO results that we parsed lazily.
+ iter = m_dwarf4_dwo_id_to_skeleton_unit.find(*dwo_id);
+ if (iter != m_dwarf4_dwo_id_to_skeleton_unit.end())
+ return iter->second;
+ return nullptr;
+}
+
+void DWARFDebugInfo::ParseUnitHeadersIfNeeded() {
+ llvm::call_once(m_units_once_flag, [&] {
+ ParseUnitsFor(DIERef::Section::DebugInfo);
+ ParseUnitsFor(DIERef::Section::DebugTypes);
+ llvm::sort(m_type_hash_to_unit_index, llvm::less_first());
+ });
+}
+
+size_t DWARFDebugInfo::GetNumUnits() {
+ ParseUnitHeadersIfNeeded();
+ return m_units.size();
+}
+
+DWARFUnit *DWARFDebugInfo::GetUnitAtIndex(size_t idx) {
+ DWARFUnit *cu = nullptr;
+ if (idx < GetNumUnits())
+ cu = m_units[idx].get();
+ return cu;
+}
+
+uint32_t DWARFDebugInfo::FindUnitIndex(DIERef::Section section,
+ dw_offset_t offset) {
+ ParseUnitHeadersIfNeeded();
+
+ // llvm::lower_bound is not used as for DIE offsets it would still return
+ // index +1 and GetOffset() returning index itself would be a special case.
+ auto pos = llvm::upper_bound(
+ m_units, std::make_pair(section, offset),
+ [](const std::pair<DIERef::Section, dw_offset_t> &lhs,
+ const DWARFUnitSP &rhs) {
+ return lhs < std::make_pair(rhs->GetDebugSection(), rhs->GetOffset());
+ });
+ uint32_t idx = std::distance(m_units.begin(), pos);
+ if (idx == 0)
+ return DW_INVALID_INDEX;
+ return idx - 1;
+}
+
+DWARFUnit *DWARFDebugInfo::GetUnitAtOffset(DIERef::Section section,
+ dw_offset_t cu_offset,
+ uint32_t *idx_ptr) {
+ uint32_t idx = FindUnitIndex(section, cu_offset);
+ DWARFUnit *result = GetUnitAtIndex(idx);
+ if (result && result->GetOffset() != cu_offset) {
+ result = nullptr;
+ idx = DW_INVALID_INDEX;
+ }
+ if (idx_ptr)
+ *idx_ptr = idx;
+ return result;
+}
+
+DWARFUnit *
+DWARFDebugInfo::GetUnitContainingDIEOffset(DIERef::Section section,
+ dw_offset_t die_offset) {
+ uint32_t idx = FindUnitIndex(section, die_offset);
+ DWARFUnit *result = GetUnitAtIndex(idx);
+ if (result && !result->ContainsDIEOffset(die_offset))
+ return nullptr;
+ return result;
+}
+
+const std::shared_ptr<SymbolFileDWARFDwo> &DWARFDebugInfo::GetDwpSymbolFile() {
+ return m_dwarf.GetDwpSymbolFile();
+}
+
+DWARFTypeUnit *DWARFDebugInfo::GetTypeUnitForHash(uint64_t hash) {
+ auto pos = llvm::lower_bound(m_type_hash_to_unit_index,
+ std::make_pair(hash, 0u), llvm::less_first());
+ if (pos == m_type_hash_to_unit_index.end() || pos->first != hash)
+ return nullptr;
+ return llvm::cast<DWARFTypeUnit>(GetUnitAtIndex(pos->second));
+}
+
+bool DWARFDebugInfo::ContainsTypeUnits() {
+ ParseUnitHeadersIfNeeded();
+ return !m_type_hash_to_unit_index.empty();
+}
+
+// GetDIE()
+//
+// Get the DIE (Debug Information Entry) with the specified offset.
+DWARFDIE
+DWARFDebugInfo::GetDIE(DIERef::Section section, dw_offset_t die_offset) {
+ if (DWARFUnit *cu = GetUnitContainingDIEOffset(section, die_offset))
+ return cu->GetNonSkeletonUnit().GetDIE(die_offset);
+ return DWARFDIE(); // Not found
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h
new file mode 100644
index 000000000000..598739bf3cb9
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h
@@ -0,0 +1,89 @@
+//===-- DWARFDebugInfo.h ----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGINFO_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGINFO_H
+
+#include <map>
+#include <vector>
+
+#include "DWARFDIE.h"
+#include "DWARFTypeUnit.h"
+#include "DWARFUnit.h"
+#include "SymbolFileDWARF.h"
+#include "lldb/lldb-private.h"
+#include "llvm/Support/Error.h"
+
+namespace lldb_private::plugin {
+namespace dwarf {
+class DWARFContext;
+
+class DWARFDebugInfo {
+public:
+ typedef dw_offset_t (*Callback)(SymbolFileDWARF *dwarf2Data, DWARFUnit *cu,
+ DWARFDebugInfoEntry *die,
+ const dw_offset_t next_offset,
+ const uint32_t depth, void *userData);
+
+ explicit DWARFDebugInfo(SymbolFileDWARF &dwarf, DWARFContext &context);
+
+ size_t GetNumUnits();
+ DWARFUnit *GetUnitAtIndex(size_t idx);
+ DWARFUnit *GetUnitAtOffset(DIERef::Section section, dw_offset_t cu_offset,
+ uint32_t *idx_ptr = nullptr);
+ DWARFUnit *GetUnitContainingDIEOffset(DIERef::Section section,
+ dw_offset_t die_offset);
+ DWARFUnit *GetSkeletonUnit(DWARFUnit *dwo_unit);
+ DWARFTypeUnit *GetTypeUnitForHash(uint64_t hash);
+ bool ContainsTypeUnits();
+ DWARFDIE GetDIE(DIERef::Section section, dw_offset_t die_offset);
+
+ enum {
+ eDumpFlag_Verbose = (1 << 0), // Verbose dumping
+ eDumpFlag_ShowForm = (1 << 1), // Show the DW_form type
+ eDumpFlag_ShowAncestors =
+ (1 << 2) // Show all parent DIEs when dumping single DIEs
+ };
+
+ const DWARFDebugAranges &GetCompileUnitAranges();
+
+ const std::shared_ptr<SymbolFileDWARFDwo> &GetDwpSymbolFile();
+
+protected:
+ typedef std::vector<DWARFUnitSP> UnitColl;
+
+ SymbolFileDWARF &m_dwarf;
+ DWARFContext &m_context;
+
+ llvm::once_flag m_units_once_flag;
+ UnitColl m_units;
+
+ std::unique_ptr<DWARFDebugAranges>
+ m_cu_aranges_up; // A quick address to compile unit table
+
+ std::vector<std::pair<uint64_t, uint32_t>> m_type_hash_to_unit_index;
+ llvm::DenseMap<uint64_t, DWARFUnit *> m_dwarf5_dwo_id_to_skeleton_unit;
+ llvm::DenseMap<uint64_t, DWARFUnit *> m_dwarf4_dwo_id_to_skeleton_unit;
+ llvm::once_flag m_dwarf4_dwo_id_to_skeleton_unit_once_flag;
+
+private:
+ // All parsing needs to be done partially any managed by this class as
+ // accessors are called.
+ void ParseUnitHeadersIfNeeded();
+
+ void ParseUnitsFor(DIERef::Section section);
+
+ uint32_t FindUnitIndex(DIERef::Section section, dw_offset_t offset);
+
+ DWARFDebugInfo(const DWARFDebugInfo &) = delete;
+ const DWARFDebugInfo &operator=(const DWARFDebugInfo &) = delete;
+};
+} // namespace dwarf
+} // namespace lldb_private::plugin
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGINFO_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
new file mode 100644
index 000000000000..e2660735ea7d
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
@@ -0,0 +1,662 @@
+//===-- DWARFDebugInfoEntry.cpp -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugInfoEntry.h"
+
+#include <cassert>
+
+#include <algorithm>
+#include <limits>
+#include <optional>
+
+#include "llvm/Support/LEB128.h"
+
+#include "lldb/Core/Module.h"
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StreamString.h"
+
+#include "DWARFCompileUnit.h"
+#include "DWARFDebugAranges.h"
+#include "DWARFDebugInfo.h"
+#include "DWARFDebugRanges.h"
+#include "DWARFDeclContext.h"
+#include "DWARFFormValue.h"
+#include "DWARFUnit.h"
+#include "SymbolFileDWARF.h"
+#include "SymbolFileDWARFDwo.h"
+
+#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
+
+using namespace lldb_private;
+using namespace lldb_private::dwarf;
+using namespace lldb_private::plugin::dwarf;
+extern int g_verbose;
+
+// Extract a debug info entry for a given DWARFUnit from the data
+// starting at the offset in offset_ptr
+bool DWARFDebugInfoEntry::Extract(const DWARFDataExtractor &data,
+ const DWARFUnit &unit,
+ lldb::offset_t *offset_ptr) {
+ m_offset = *offset_ptr;
+ auto report_error = [&](const char *fmt, const auto &...vals) {
+ unit.GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(
+ "[{0:x16}]: {1}, please file a bug and "
+ "attach the file at the start of this error message",
+ static_cast<uint64_t>(m_offset), llvm::formatv(fmt, vals...));
+ *offset_ptr = std::numeric_limits<lldb::offset_t>::max();
+ return false;
+ };
+
+ m_parent_idx = 0;
+ m_sibling_idx = 0;
+ const uint64_t abbr_idx = data.GetULEB128(offset_ptr);
+ if (abbr_idx > std::numeric_limits<uint16_t>::max())
+ return report_error("abbreviation code {0} too big", abbr_idx);
+ m_abbr_idx = abbr_idx;
+
+ if (m_abbr_idx == 0) {
+ m_tag = llvm::dwarf::DW_TAG_null;
+ m_has_children = false;
+ return true; // NULL debug tag entry
+ }
+
+ const auto *abbrevDecl = GetAbbreviationDeclarationPtr(&unit);
+ if (abbrevDecl == nullptr)
+ return report_error("invalid abbreviation code {0}", abbr_idx);
+
+ m_tag = abbrevDecl->getTag();
+ m_has_children = abbrevDecl->hasChildren();
+ // Skip all data in the .debug_info or .debug_types for the attributes
+ for (const auto &attribute : abbrevDecl->attributes()) {
+ if (DWARFFormValue::SkipValue(attribute.Form, data, offset_ptr, &unit))
+ continue;
+
+ return report_error("Unsupported DW_FORM_{1:x}", attribute.Form);
+ }
+ return true;
+}
+
+static DWARFRangeList GetRangesOrReportError(DWARFUnit &unit,
+ const DWARFDebugInfoEntry &die,
+ const DWARFFormValue &value) {
+ llvm::Expected<DWARFRangeList> expected_ranges =
+ (value.Form() == DW_FORM_rnglistx)
+ ? unit.FindRnglistFromIndex(value.Unsigned())
+ : unit.FindRnglistFromOffset(value.Unsigned());
+ if (expected_ranges)
+ return std::move(*expected_ranges);
+
+ unit.GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(
+ "[{0:x16}]: DIE has DW_AT_ranges({1} {2:x16}) attribute, but "
+ "range extraction failed ({3}), please file a bug "
+ "and attach the file at the start of this error message",
+ die.GetOffset(),
+ llvm::dwarf::FormEncodingString(value.Form()).str().c_str(),
+ value.Unsigned(), toString(expected_ranges.takeError()).c_str());
+ return DWARFRangeList();
+}
+
+static void ExtractAttrAndFormValue(
+ const llvm::DWARFAbbreviationDeclaration::AttributeSpec &attr_spec,
+ dw_attr_t &attr, DWARFFormValue &form_value) {
+ attr = attr_spec.Attr;
+ form_value.FormRef() = attr_spec.Form;
+ if (attr_spec.isImplicitConst())
+ form_value.SetSigned(attr_spec.getImplicitConstValue());
+}
+
+// GetDIENamesAndRanges
+//
+// Gets the valid address ranges for a given DIE by looking for a
+// DW_AT_low_pc/DW_AT_high_pc pair, DW_AT_entry_pc, or DW_AT_ranges attributes.
+bool DWARFDebugInfoEntry::GetDIENamesAndRanges(
+ DWARFUnit *cu, const char *&name, const char *&mangled,
+ DWARFRangeList &ranges, std::optional<int> &decl_file,
+ std::optional<int> &decl_line, std::optional<int> &decl_column,
+ std::optional<int> &call_file, std::optional<int> &call_line,
+ std::optional<int> &call_column, DWARFExpressionList *frame_base) const {
+ dw_addr_t lo_pc = LLDB_INVALID_ADDRESS;
+ dw_addr_t hi_pc = LLDB_INVALID_ADDRESS;
+ std::vector<DWARFDIE> dies;
+ bool set_frame_base_loclist_addr = false;
+
+ SymbolFileDWARF &dwarf = cu->GetSymbolFileDWARF();
+ lldb::ModuleSP module = dwarf.GetObjectFile()->GetModule();
+
+ if (const auto *abbrevDecl = GetAbbreviationDeclarationPtr(cu)) {
+ const DWARFDataExtractor &data = cu->GetData();
+ lldb::offset_t offset = GetFirstAttributeOffset();
+
+ if (!data.ValidOffset(offset))
+ return false;
+
+ bool do_offset = false;
+
+ for (const auto &attribute : abbrevDecl->attributes()) {
+ DWARFFormValue form_value(cu);
+ dw_attr_t attr;
+ ExtractAttrAndFormValue(attribute, attr, form_value);
+
+ if (form_value.ExtractValue(data, &offset)) {
+ switch (attr) {
+ case DW_AT_low_pc:
+ lo_pc = form_value.Address();
+
+ if (do_offset)
+ hi_pc += lo_pc;
+ do_offset = false;
+ break;
+
+ case DW_AT_entry_pc:
+ lo_pc = form_value.Address();
+ break;
+
+ case DW_AT_high_pc:
+ if (form_value.Form() == DW_FORM_addr ||
+ form_value.Form() == DW_FORM_addrx ||
+ form_value.Form() == DW_FORM_GNU_addr_index) {
+ hi_pc = form_value.Address();
+ } else {
+ hi_pc = form_value.Unsigned();
+ if (lo_pc == LLDB_INVALID_ADDRESS)
+ do_offset = hi_pc != LLDB_INVALID_ADDRESS;
+ else
+ hi_pc += lo_pc; // DWARF 4 introduces <offset-from-lo-pc> to save
+ // on relocations
+ }
+ break;
+
+ case DW_AT_ranges:
+ ranges = GetRangesOrReportError(*cu, *this, form_value);
+ break;
+
+ case DW_AT_name:
+ if (name == nullptr)
+ name = form_value.AsCString();
+ break;
+
+ case DW_AT_MIPS_linkage_name:
+ case DW_AT_linkage_name:
+ if (mangled == nullptr)
+ mangled = form_value.AsCString();
+ break;
+
+ case DW_AT_abstract_origin:
+ dies.push_back(form_value.Reference());
+ break;
+
+ case DW_AT_specification:
+ dies.push_back(form_value.Reference());
+ break;
+
+ case DW_AT_decl_file:
+ if (!decl_file)
+ decl_file = form_value.Unsigned();
+ break;
+
+ case DW_AT_decl_line:
+ if (!decl_line)
+ decl_line = form_value.Unsigned();
+ break;
+
+ case DW_AT_decl_column:
+ if (!decl_column)
+ decl_column = form_value.Unsigned();
+ break;
+
+ case DW_AT_call_file:
+ if (!call_file)
+ call_file = form_value.Unsigned();
+ break;
+
+ case DW_AT_call_line:
+ if (!call_line)
+ call_line = form_value.Unsigned();
+ break;
+
+ case DW_AT_call_column:
+ if (!call_column)
+ call_column = form_value.Unsigned();
+ break;
+
+ case DW_AT_frame_base:
+ if (frame_base) {
+ if (form_value.BlockData()) {
+ uint32_t block_offset =
+ form_value.BlockData() - data.GetDataStart();
+ uint32_t block_length = form_value.Unsigned();
+ *frame_base =
+ DWARFExpressionList(module,
+ DWARFExpression(DataExtractor(
+ data, block_offset, block_length)),
+ cu);
+ } else {
+ DataExtractor data = cu->GetLocationData();
+ const dw_offset_t offset = form_value.Unsigned();
+ if (data.ValidOffset(offset)) {
+ data = DataExtractor(data, offset, data.GetByteSize() - offset);
+ if (lo_pc != LLDB_INVALID_ADDRESS) {
+ assert(lo_pc >= cu->GetBaseAddress());
+ DWARFExpression::ParseDWARFLocationList(cu, data, frame_base);
+ frame_base->SetFuncFileAddress(lo_pc);
+ } else
+ set_frame_base_loclist_addr = true;
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ if (ranges.IsEmpty()) {
+ if (lo_pc != LLDB_INVALID_ADDRESS) {
+ if (hi_pc != LLDB_INVALID_ADDRESS && hi_pc > lo_pc)
+ ranges.Append(DWARFRangeList::Entry(lo_pc, hi_pc - lo_pc));
+ else
+ ranges.Append(DWARFRangeList::Entry(lo_pc, 0));
+ }
+ }
+
+ if (set_frame_base_loclist_addr) {
+ dw_addr_t lowest_range_pc = ranges.GetMinRangeBase(0);
+ assert(lowest_range_pc >= cu->GetBaseAddress());
+ frame_base->SetFuncFileAddress(lowest_range_pc);
+ }
+
+ if (ranges.IsEmpty() || name == nullptr || mangled == nullptr) {
+ for (const DWARFDIE &die : dies) {
+ if (die) {
+ die.GetDIE()->GetDIENamesAndRanges(die.GetCU(), name, mangled, ranges,
+ decl_file, decl_line, decl_column,
+ call_file, call_line, call_column);
+ }
+ }
+ }
+ return !ranges.IsEmpty();
+}
+
+// Get all attribute values for a given DIE, including following any
+// specification or abstract origin attributes and including those in the
+// results. Any duplicate attributes will have the first instance take
+// precedence (this can happen for declaration attributes).
+void DWARFDebugInfoEntry::GetAttributes(DWARFUnit *cu,
+ DWARFAttributes &attributes,
+ Recurse recurse,
+ uint32_t curr_depth) const {
+ const auto *abbrevDecl = GetAbbreviationDeclarationPtr(cu);
+ if (!abbrevDecl) {
+ attributes.Clear();
+ return;
+ }
+
+ const DWARFDataExtractor &data = cu->GetData();
+ lldb::offset_t offset = GetFirstAttributeOffset();
+
+ for (const auto &attribute : abbrevDecl->attributes()) {
+ DWARFFormValue form_value(cu);
+ dw_attr_t attr;
+ ExtractAttrAndFormValue(attribute, attr, form_value);
+
+ // If we are tracking down DW_AT_specification or DW_AT_abstract_origin
+ // attributes, the depth will be non-zero. We need to omit certain
+ // attributes that don't make sense.
+ switch (attr) {
+ case DW_AT_sibling:
+ case DW_AT_declaration:
+ if (curr_depth > 0) {
+ // This attribute doesn't make sense when combined with the DIE that
+ // references this DIE. We know a DIE is referencing this DIE because
+ // curr_depth is not zero
+ break;
+ }
+ [[fallthrough]];
+ default:
+ attributes.Append(form_value, offset, attr);
+ break;
+ }
+
+ if (recurse == Recurse::yes &&
+ ((attr == DW_AT_specification) || (attr == DW_AT_abstract_origin))) {
+ if (form_value.ExtractValue(data, &offset)) {
+ DWARFDIE spec_die = form_value.Reference();
+ if (spec_die)
+ spec_die.GetDIE()->GetAttributes(spec_die.GetCU(), attributes,
+ recurse, curr_depth + 1);
+ }
+ } else {
+ const dw_form_t form = form_value.Form();
+ std::optional<uint8_t> fixed_skip_size =
+ DWARFFormValue::GetFixedSize(form, cu);
+ if (fixed_skip_size)
+ offset += *fixed_skip_size;
+ else
+ DWARFFormValue::SkipValue(form, data, &offset, cu);
+ }
+ }
+}
+
+// GetAttributeValue
+//
+// Get the value of an attribute and return the .debug_info or .debug_types
+// offset of the attribute if it was properly extracted into form_value,
+// or zero if we fail since an offset of zero is invalid for an attribute (it
+// would be a compile unit header).
+dw_offset_t DWARFDebugInfoEntry::GetAttributeValue(
+ const DWARFUnit *cu, const dw_attr_t attr, DWARFFormValue &form_value,
+ dw_offset_t *end_attr_offset_ptr,
+ bool check_specification_or_abstract_origin) const {
+ if (const auto *abbrevDecl = GetAbbreviationDeclarationPtr(cu)) {
+ std::optional<uint32_t> attr_idx = abbrevDecl->findAttributeIndex(attr);
+
+ if (attr_idx) {
+ const DWARFDataExtractor &data = cu->GetData();
+ lldb::offset_t offset = GetFirstAttributeOffset();
+
+ uint32_t idx = 0;
+ while (idx < *attr_idx)
+ DWARFFormValue::SkipValue(abbrevDecl->getFormByIndex(idx++), data,
+ &offset, cu);
+
+ const dw_offset_t attr_offset = offset;
+ form_value.SetUnit(cu);
+ form_value.SetForm(abbrevDecl->getFormByIndex(idx));
+ if (form_value.ExtractValue(data, &offset)) {
+ if (end_attr_offset_ptr)
+ *end_attr_offset_ptr = offset;
+ return attr_offset;
+ }
+ }
+ }
+
+ if (check_specification_or_abstract_origin) {
+ if (GetAttributeValue(cu, DW_AT_specification, form_value)) {
+ DWARFDIE die = form_value.Reference();
+ if (die) {
+ dw_offset_t die_offset = die.GetDIE()->GetAttributeValue(
+ die.GetCU(), attr, form_value, end_attr_offset_ptr, false);
+ if (die_offset)
+ return die_offset;
+ }
+ }
+
+ if (GetAttributeValue(cu, DW_AT_abstract_origin, form_value)) {
+ DWARFDIE die = form_value.Reference();
+ if (die) {
+ dw_offset_t die_offset = die.GetDIE()->GetAttributeValue(
+ die.GetCU(), attr, form_value, end_attr_offset_ptr, false);
+ if (die_offset)
+ return die_offset;
+ }
+ }
+ }
+ return 0;
+}
+
+// GetAttributeValueAsString
+//
+// Get the value of an attribute as a string return it. The resulting pointer
+// to the string data exists within the supplied SymbolFileDWARF and will only
+// be available as long as the SymbolFileDWARF is still around and it's content
+// doesn't change.
+const char *DWARFDebugInfoEntry::GetAttributeValueAsString(
+ const DWARFUnit *cu, const dw_attr_t attr, const char *fail_value,
+ bool check_specification_or_abstract_origin) const {
+ DWARFFormValue form_value;
+ if (GetAttributeValue(cu, attr, form_value, nullptr,
+ check_specification_or_abstract_origin))
+ return form_value.AsCString();
+ return fail_value;
+}
+
+// GetAttributeValueAsUnsigned
+//
+// Get the value of an attribute as unsigned and return it.
+uint64_t DWARFDebugInfoEntry::GetAttributeValueAsUnsigned(
+ const DWARFUnit *cu, const dw_attr_t attr, uint64_t fail_value,
+ bool check_specification_or_abstract_origin) const {
+ DWARFFormValue form_value;
+ if (GetAttributeValue(cu, attr, form_value, nullptr,
+ check_specification_or_abstract_origin))
+ return form_value.Unsigned();
+ return fail_value;
+}
+
+std::optional<uint64_t>
+DWARFDebugInfoEntry::GetAttributeValueAsOptionalUnsigned(
+ const DWARFUnit *cu, const dw_attr_t attr,
+ bool check_specification_or_abstract_origin) const {
+ DWARFFormValue form_value;
+ if (GetAttributeValue(cu, attr, form_value, nullptr,
+ check_specification_or_abstract_origin))
+ return form_value.Unsigned();
+ return std::nullopt;
+}
+
+// GetAttributeValueAsReference
+//
+// Get the value of an attribute as reference and fix up and compile unit
+// relative offsets as needed.
+DWARFDIE DWARFDebugInfoEntry::GetAttributeValueAsReference(
+ const DWARFUnit *cu, const dw_attr_t attr,
+ bool check_specification_or_abstract_origin) const {
+ DWARFFormValue form_value;
+ if (GetAttributeValue(cu, attr, form_value, nullptr,
+ check_specification_or_abstract_origin))
+ return form_value.Reference();
+ return {};
+}
+
+uint64_t DWARFDebugInfoEntry::GetAttributeValueAsAddress(
+ const DWARFUnit *cu, const dw_attr_t attr, uint64_t fail_value,
+ bool check_specification_or_abstract_origin) const {
+ DWARFFormValue form_value;
+ if (GetAttributeValue(cu, attr, form_value, nullptr,
+ check_specification_or_abstract_origin))
+ return form_value.Address();
+ return fail_value;
+}
+
+// GetAttributeHighPC
+//
+// Get the hi_pc, adding hi_pc to lo_pc when specified as an <offset-from-low-
+// pc>.
+//
+// Returns the hi_pc or fail_value.
+dw_addr_t DWARFDebugInfoEntry::GetAttributeHighPC(
+ const DWARFUnit *cu, dw_addr_t lo_pc, uint64_t fail_value,
+ bool check_specification_or_abstract_origin) const {
+ DWARFFormValue form_value;
+ if (GetAttributeValue(cu, DW_AT_high_pc, form_value, nullptr,
+ check_specification_or_abstract_origin)) {
+ dw_form_t form = form_value.Form();
+ if (form == DW_FORM_addr || form == DW_FORM_addrx ||
+ form == DW_FORM_GNU_addr_index)
+ return form_value.Address();
+
+ // DWARF4 can specify the hi_pc as an <offset-from-lowpc>
+ return lo_pc + form_value.Unsigned();
+ }
+ return fail_value;
+}
+
+// GetAttributeAddressRange
+//
+// Get the lo_pc and hi_pc, adding hi_pc to lo_pc when specified as an <offset-
+// from-low-pc>.
+//
+// Returns true or sets lo_pc and hi_pc to fail_value.
+bool DWARFDebugInfoEntry::GetAttributeAddressRange(
+ const DWARFUnit *cu, dw_addr_t &lo_pc, dw_addr_t &hi_pc,
+ uint64_t fail_value, bool check_specification_or_abstract_origin) const {
+ lo_pc = GetAttributeValueAsAddress(cu, DW_AT_low_pc, fail_value,
+ check_specification_or_abstract_origin);
+ if (lo_pc != fail_value) {
+ hi_pc = GetAttributeHighPC(cu, lo_pc, fail_value,
+ check_specification_or_abstract_origin);
+ if (hi_pc != fail_value)
+ return true;
+ }
+ lo_pc = fail_value;
+ hi_pc = fail_value;
+ return false;
+}
+
+DWARFRangeList DWARFDebugInfoEntry::GetAttributeAddressRanges(
+ DWARFUnit *cu, bool check_hi_lo_pc,
+ bool check_specification_or_abstract_origin) const {
+
+ DWARFFormValue form_value;
+ if (GetAttributeValue(cu, DW_AT_ranges, form_value))
+ return GetRangesOrReportError(*cu, *this, form_value);
+
+ DWARFRangeList ranges;
+ if (check_hi_lo_pc) {
+ dw_addr_t lo_pc = LLDB_INVALID_ADDRESS;
+ dw_addr_t hi_pc = LLDB_INVALID_ADDRESS;
+ if (GetAttributeAddressRange(cu, lo_pc, hi_pc, LLDB_INVALID_ADDRESS,
+ check_specification_or_abstract_origin)) {
+ if (lo_pc < hi_pc)
+ ranges.Append(DWARFRangeList::Entry(lo_pc, hi_pc - lo_pc));
+ }
+ }
+ return ranges;
+}
+
+// GetName
+//
+// Get value of the DW_AT_name attribute and return it if one exists, else
+// return NULL.
+const char *DWARFDebugInfoEntry::GetName(const DWARFUnit *cu) const {
+ return GetAttributeValueAsString(cu, DW_AT_name, nullptr, true);
+}
+
+// GetMangledName
+//
+// Get value of the DW_AT_MIPS_linkage_name attribute and return it if one
+// exists, else return the value of the DW_AT_name attribute
+const char *
+DWARFDebugInfoEntry::GetMangledName(const DWARFUnit *cu,
+ bool substitute_name_allowed) const {
+ const char *name = nullptr;
+
+ name = GetAttributeValueAsString(cu, DW_AT_MIPS_linkage_name, nullptr, true);
+ if (name)
+ return name;
+
+ name = GetAttributeValueAsString(cu, DW_AT_linkage_name, nullptr, true);
+ if (name)
+ return name;
+
+ if (!substitute_name_allowed)
+ return nullptr;
+
+ name = GetAttributeValueAsString(cu, DW_AT_name, nullptr, true);
+ return name;
+}
+
+// GetPubname
+//
+// Get value the name for a DIE as it should appear for a .debug_pubnames or
+// .debug_pubtypes section.
+const char *DWARFDebugInfoEntry::GetPubname(const DWARFUnit *cu) const {
+ const char *name = nullptr;
+ if (!cu)
+ return name;
+
+ name = GetAttributeValueAsString(cu, DW_AT_MIPS_linkage_name, nullptr, true);
+ if (name)
+ return name;
+
+ name = GetAttributeValueAsString(cu, DW_AT_linkage_name, nullptr, true);
+ if (name)
+ return name;
+
+ name = GetAttributeValueAsString(cu, DW_AT_name, nullptr, true);
+ return name;
+}
+
+/// This function is builds a table very similar to the standard .debug_aranges
+/// table, except that the actual DIE offset for the function is placed in the
+/// table instead of the compile unit offset.
+void DWARFDebugInfoEntry::BuildFunctionAddressRangeTable(
+ DWARFUnit *cu, DWARFDebugAranges *debug_aranges) const {
+ if (m_tag) {
+ if (m_tag == DW_TAG_subprogram) {
+ DWARFRangeList ranges =
+ GetAttributeAddressRanges(cu, /*check_hi_lo_pc=*/true);
+ for (const auto &r : ranges) {
+ debug_aranges->AppendRange(GetOffset(), r.GetRangeBase(),
+ r.GetRangeEnd());
+ }
+ }
+
+ const DWARFDebugInfoEntry *child = GetFirstChild();
+ while (child) {
+ child->BuildFunctionAddressRangeTable(cu, debug_aranges);
+ child = child->GetSibling();
+ }
+ }
+}
+
+lldb::offset_t DWARFDebugInfoEntry::GetFirstAttributeOffset() const {
+ return GetOffset() + llvm::getULEB128Size(m_abbr_idx);
+}
+
+const llvm::DWARFAbbreviationDeclaration *
+DWARFDebugInfoEntry::GetAbbreviationDeclarationPtr(const DWARFUnit *cu) const {
+ if (!cu)
+ return nullptr;
+
+ const llvm::DWARFAbbreviationDeclarationSet *abbrev_set =
+ cu->GetAbbreviations();
+ if (!abbrev_set)
+ return nullptr;
+
+ return abbrev_set->getAbbreviationDeclaration(m_abbr_idx);
+}
+
+bool DWARFDebugInfoEntry::IsGlobalOrStaticScopeVariable() const {
+ if (Tag() != DW_TAG_variable)
+ return false;
+ const DWARFDebugInfoEntry *parent_die = GetParent();
+ while (parent_die != nullptr) {
+ switch (parent_die->Tag()) {
+ case DW_TAG_subprogram:
+ case DW_TAG_lexical_block:
+ case DW_TAG_inlined_subroutine:
+ return false;
+
+ case DW_TAG_compile_unit:
+ case DW_TAG_partial_unit:
+ return true;
+
+ default:
+ break;
+ }
+ parent_die = parent_die->GetParent();
+ }
+ return false;
+}
+
+bool DWARFDebugInfoEntry::operator==(const DWARFDebugInfoEntry &rhs) const {
+ return m_offset == rhs.m_offset && m_parent_idx == rhs.m_parent_idx &&
+ m_sibling_idx == rhs.m_sibling_idx &&
+ m_abbr_idx == rhs.m_abbr_idx && m_has_children == rhs.m_has_children &&
+ m_tag == rhs.m_tag;
+}
+
+bool DWARFDebugInfoEntry::operator!=(const DWARFDebugInfoEntry &rhs) const {
+ return !(*this == rhs);
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h
new file mode 100644
index 000000000000..3816c6500717
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h
@@ -0,0 +1,191 @@
+//===-- DWARFDebugInfoEntry.h -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGINFOENTRY_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGINFOENTRY_H
+
+#include "SymbolFileDWARF.h"
+#include "llvm/ADT/SmallVector.h"
+
+#include "DWARFAttribute.h"
+#include "DWARFBaseDIE.h"
+#include "DWARFDebugRanges.h"
+#include <map>
+#include <optional>
+#include <set>
+#include <vector>
+
+#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
+
+namespace lldb_private::plugin {
+namespace dwarf {
+class DWARFDeclContext;
+
+#define DIE_SIBLING_IDX_BITSIZE 31
+
+/// DWARFDebugInfoEntry objects assume that they are living in one big
+/// vector and do pointer arithmetic on their this pointers. Don't
+/// pass them by value. Due to the way they are constructed in a
+/// std::vector, we cannot delete the copy constructor.
+class DWARFDebugInfoEntry {
+public:
+ typedef std::vector<DWARFDebugInfoEntry> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+
+ DWARFDebugInfoEntry()
+ : m_offset(DW_INVALID_OFFSET), m_parent_idx(0), m_sibling_idx(0),
+ m_has_children(false) {}
+
+ explicit operator bool() const { return m_offset != DW_INVALID_OFFSET; }
+ bool operator==(const DWARFDebugInfoEntry &rhs) const;
+ bool operator!=(const DWARFDebugInfoEntry &rhs) const;
+
+ void BuildFunctionAddressRangeTable(DWARFUnit *cu,
+ DWARFDebugAranges *debug_aranges) const;
+
+ bool Extract(const DWARFDataExtractor &data, const DWARFUnit &cu,
+ lldb::offset_t *offset_ptr);
+
+ using Recurse = DWARFBaseDIE::Recurse;
+ DWARFAttributes GetAttributes(DWARFUnit *cu,
+ Recurse recurse = Recurse::yes) const {
+ DWARFAttributes attrs;
+ GetAttributes(cu, attrs, recurse, 0 /* curr_depth */);
+ return attrs;
+ }
+
+ dw_offset_t
+ GetAttributeValue(const DWARFUnit *cu, const dw_attr_t attr,
+ DWARFFormValue &formValue,
+ dw_offset_t *end_attr_offset_ptr = nullptr,
+ bool check_specification_or_abstract_origin = false) const;
+
+ const char *GetAttributeValueAsString(
+ const DWARFUnit *cu, const dw_attr_t attr, const char *fail_value,
+ bool check_specification_or_abstract_origin = false) const;
+
+ uint64_t GetAttributeValueAsUnsigned(
+ const DWARFUnit *cu, const dw_attr_t attr, uint64_t fail_value,
+ bool check_specification_or_abstract_origin = false) const;
+
+ std::optional<uint64_t> GetAttributeValueAsOptionalUnsigned(
+ const DWARFUnit *cu, const dw_attr_t attr,
+ bool check_specification_or_abstract_origin = false) const;
+
+ DWARFDIE GetAttributeValueAsReference(
+ const DWARFUnit *cu, const dw_attr_t attr,
+ bool check_specification_or_abstract_origin = false) const;
+
+ uint64_t GetAttributeValueAsAddress(
+ const DWARFUnit *cu, const dw_attr_t attr, uint64_t fail_value,
+ bool check_specification_or_abstract_origin = false) const;
+
+ dw_addr_t
+ GetAttributeHighPC(const DWARFUnit *cu, dw_addr_t lo_pc, uint64_t fail_value,
+ bool check_specification_or_abstract_origin = false) const;
+
+ bool GetAttributeAddressRange(
+ const DWARFUnit *cu, dw_addr_t &lo_pc, dw_addr_t &hi_pc,
+ uint64_t fail_value,
+ bool check_specification_or_abstract_origin = false) const;
+
+ DWARFRangeList GetAttributeAddressRanges(
+ DWARFUnit *cu, bool check_hi_lo_pc,
+ bool check_specification_or_abstract_origin = false) const;
+
+ const char *GetName(const DWARFUnit *cu) const;
+
+ const char *GetMangledName(const DWARFUnit *cu,
+ bool substitute_name_allowed = true) const;
+
+ const char *GetPubname(const DWARFUnit *cu) const;
+
+ bool GetDIENamesAndRanges(DWARFUnit *cu, const char *&name,
+ const char *&mangled, DWARFRangeList &rangeList,
+ std::optional<int> &decl_file,
+ std::optional<int> &decl_line,
+ std::optional<int> &decl_column,
+ std::optional<int> &call_file,
+ std::optional<int> &call_line,
+ std::optional<int> &call_column,
+ DWARFExpressionList *frame_base = nullptr) const;
+
+ const llvm::DWARFAbbreviationDeclaration *
+ GetAbbreviationDeclarationPtr(const DWARFUnit *cu) const;
+
+ lldb::offset_t GetFirstAttributeOffset() const;
+
+ dw_tag_t Tag() const { return m_tag; }
+
+ bool IsNULL() const { return m_abbr_idx == 0; }
+
+ dw_offset_t GetOffset() const { return m_offset; }
+
+ bool HasChildren() const { return m_has_children; }
+
+ void SetHasChildren(bool b) { m_has_children = b; }
+
+ // We know we are kept in a vector of contiguous entries, so we know
+ // our parent will be some index behind "this".
+ DWARFDebugInfoEntry *GetParent() {
+ return m_parent_idx > 0 ? this - m_parent_idx : nullptr;
+ }
+ const DWARFDebugInfoEntry *GetParent() const {
+ return m_parent_idx > 0 ? this - m_parent_idx : nullptr;
+ }
+ // We know we are kept in a vector of contiguous entries, so we know
+ // our sibling will be some index after "this".
+ DWARFDebugInfoEntry *GetSibling() {
+ return m_sibling_idx > 0 ? this + m_sibling_idx : nullptr;
+ }
+ const DWARFDebugInfoEntry *GetSibling() const {
+ return m_sibling_idx > 0 ? this + m_sibling_idx : nullptr;
+ }
+ // We know we are kept in a vector of contiguous entries, so we know
+ // we don't need to store our child pointer, if we have a child it will
+ // be the next entry in the list...
+ DWARFDebugInfoEntry *GetFirstChild() {
+ return HasChildren() ? this + 1 : nullptr;
+ }
+ const DWARFDebugInfoEntry *GetFirstChild() const {
+ return HasChildren() ? this + 1 : nullptr;
+ }
+
+ void SetSiblingIndex(uint32_t idx) { m_sibling_idx = idx; }
+ void SetParentIndex(uint32_t idx) { m_parent_idx = idx; }
+
+ // This function returns true if the variable scope is either
+ // global or (file-static). It will return false for static variables
+ // that are local to a function, as they have local scope.
+ bool IsGlobalOrStaticScopeVariable() const;
+
+protected:
+ // Up to 2TB offset within the .debug_info/.debug_types
+ dw_offset_t m_offset : DW_DIE_OFFSET_MAX_BITSIZE;
+ // How many to subtract from "this" to get the parent. If zero this die has no
+ // parent
+ dw_offset_t m_parent_idx : 64 - DW_DIE_OFFSET_MAX_BITSIZE;
+ // How many to add to "this" to get the sibling.
+ // If it is zero, then the DIE doesn't have children,
+ // or the DWARF claimed it had children but the DIE
+ // only contained a single NULL terminating child.
+ uint32_t m_sibling_idx : 31, m_has_children : 1;
+ uint16_t m_abbr_idx = 0;
+ /// A copy of the DW_TAG value so we don't have to go through the compile
+ /// unit abbrev table
+ dw_tag_t m_tag = llvm::dwarf::DW_TAG_null;
+
+private:
+ void GetAttributes(DWARFUnit *cu, DWARFAttributes &attrs, Recurse recurse,
+ uint32_t curr_depth) const;
+};
+} // namespace dwarf
+} // namespace lldb_private::plugin
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGINFOENTRY_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacro.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacro.cpp
new file mode 100644
index 000000000000..2cd84bc55b75
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacro.cpp
@@ -0,0 +1,128 @@
+//===-- DWARFDebugMacro.cpp -----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugMacro.h"
+#include "SymbolFileDWARF.h"
+
+#include "lldb/Symbol/DebugMacros.h"
+
+#include "DWARFDataExtractor.h"
+
+using namespace lldb_private;
+using namespace lldb_private::dwarf;
+using namespace lldb_private::plugin::dwarf;
+
+DWARFDebugMacroHeader
+DWARFDebugMacroHeader::ParseHeader(const DWARFDataExtractor &debug_macro_data,
+ lldb::offset_t *offset) {
+ DWARFDebugMacroHeader header;
+
+ // Skip over the version field in header.
+ header.m_version = debug_macro_data.GetU16(offset);
+
+ uint8_t flags = debug_macro_data.GetU8(offset);
+ header.m_offset_is_64_bit = (flags & OFFSET_SIZE_MASK) != 0;
+
+ if (flags & DEBUG_LINE_OFFSET_MASK) {
+ if (header.m_offset_is_64_bit)
+ header.m_debug_line_offset = debug_macro_data.GetU64(offset);
+ else
+ header.m_debug_line_offset = debug_macro_data.GetU32(offset);
+ }
+
+ // Skip over the operands table if it is present.
+ if (flags & OPCODE_OPERANDS_TABLE_MASK)
+ SkipOperandTable(debug_macro_data, offset);
+
+ return header;
+}
+
+void DWARFDebugMacroHeader::SkipOperandTable(
+ const DWARFDataExtractor &debug_macro_data, lldb::offset_t *offset) {
+ uint8_t entry_count = debug_macro_data.GetU8(offset);
+ for (uint8_t i = 0; i < entry_count; i++) {
+ // Skip over the opcode number.
+ debug_macro_data.GetU8(offset);
+
+ uint64_t operand_count = debug_macro_data.GetULEB128(offset);
+
+ for (uint64_t j = 0; j < operand_count; j++) {
+ // Skip over the operand form
+ debug_macro_data.GetU8(offset);
+ }
+ }
+}
+
+void DWARFDebugMacroEntry::ReadMacroEntries(
+ const DWARFDataExtractor &debug_macro_data,
+ const DWARFDataExtractor &debug_str_data, const bool offset_is_64_bit,
+ lldb::offset_t *offset, SymbolFileDWARF *sym_file_dwarf,
+ DebugMacrosSP &debug_macros_sp) {
+ llvm::dwarf::MacroEntryType type =
+ static_cast<llvm::dwarf::MacroEntryType>(debug_macro_data.GetU8(offset));
+ while (type != 0) {
+ lldb::offset_t new_offset = 0, str_offset = 0;
+ uint32_t line = 0;
+ const char *macro_str = nullptr;
+ uint32_t debug_line_file_idx = 0;
+
+ switch (type) {
+ case DW_MACRO_define:
+ case DW_MACRO_undef:
+ line = debug_macro_data.GetULEB128(offset);
+ macro_str = debug_macro_data.GetCStr(offset);
+ if (type == DW_MACRO_define)
+ debug_macros_sp->AddMacroEntry(
+ DebugMacroEntry::CreateDefineEntry(line, macro_str));
+ else
+ debug_macros_sp->AddMacroEntry(
+ DebugMacroEntry::CreateUndefEntry(line, macro_str));
+ break;
+ case DW_MACRO_define_strp:
+ case DW_MACRO_undef_strp:
+ line = debug_macro_data.GetULEB128(offset);
+ if (offset_is_64_bit)
+ str_offset = debug_macro_data.GetU64(offset);
+ else
+ str_offset = debug_macro_data.GetU32(offset);
+ macro_str = debug_str_data.GetCStr(&str_offset);
+ if (type == DW_MACRO_define_strp)
+ debug_macros_sp->AddMacroEntry(
+ DebugMacroEntry::CreateDefineEntry(line, macro_str));
+ else
+ debug_macros_sp->AddMacroEntry(
+ DebugMacroEntry::CreateUndefEntry(line, macro_str));
+ break;
+ case DW_MACRO_start_file:
+ line = debug_macro_data.GetULEB128(offset);
+ debug_line_file_idx = debug_macro_data.GetULEB128(offset);
+ debug_macros_sp->AddMacroEntry(
+ DebugMacroEntry::CreateStartFileEntry(line, debug_line_file_idx));
+ break;
+ case DW_MACRO_end_file:
+ // This operation has no operands.
+ debug_macros_sp->AddMacroEntry(DebugMacroEntry::CreateEndFileEntry());
+ break;
+ case DW_MACRO_import:
+ if (offset_is_64_bit)
+ new_offset = debug_macro_data.GetU64(offset);
+ else
+ new_offset = debug_macro_data.GetU32(offset);
+ debug_macros_sp->AddMacroEntry(DebugMacroEntry::CreateIndirectEntry(
+ sym_file_dwarf->ParseDebugMacros(&new_offset)));
+ break;
+ default:
+ // TODO: Add support for other standard operations.
+ // TODO: Provide mechanism to hook handling of non-standard/extension
+ // operands.
+ return;
+ }
+ type = static_cast<llvm::dwarf::MacroEntryType>(
+ debug_macro_data.GetU8(offset));
+ }
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacro.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacro.h
new file mode 100644
index 000000000000..67d1cde8d5de
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacro.h
@@ -0,0 +1,62 @@
+//===-- DWARFDebugMacro.h ----------------------------------------*- C++
+//-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGMACRO_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGMACRO_H
+
+#include <map>
+
+#include "lldb/Core/dwarf.h"
+#include "lldb/Symbol/DebugMacros.h"
+#include "lldb/lldb-types.h"
+
+namespace lldb_private {
+class DWARFDataExtractor;
+}
+
+namespace lldb_private::plugin {
+namespace dwarf {
+class SymbolFileDWARF;
+
+class DWARFDebugMacroHeader {
+public:
+ enum HeaderFlagMask {
+ OFFSET_SIZE_MASK = 0x1,
+ DEBUG_LINE_OFFSET_MASK = 0x2,
+ OPCODE_OPERANDS_TABLE_MASK = 0x4
+ };
+
+ static DWARFDebugMacroHeader
+ ParseHeader(const DWARFDataExtractor &debug_macro_data,
+ lldb::offset_t *offset);
+
+ bool OffsetIs64Bit() const { return m_offset_is_64_bit; }
+
+private:
+ static void SkipOperandTable(const DWARFDataExtractor &debug_macro_data,
+ lldb::offset_t *offset);
+
+ uint16_t m_version = 0;
+ bool m_offset_is_64_bit = false;
+ uint64_t m_debug_line_offset = 0;
+};
+
+class DWARFDebugMacroEntry {
+public:
+ static void ReadMacroEntries(const DWARFDataExtractor &debug_macro_data,
+ const DWARFDataExtractor &debug_str_data,
+ const bool offset_is_64_bit,
+ lldb::offset_t *sect_offset,
+ SymbolFileDWARF *sym_file_dwarf,
+ DebugMacrosSP &debug_macros_sp);
+};
+} // namespace dwarf
+} // namespace lldb_private::plugin
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGMACRO_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp
new file mode 100644
index 000000000000..fd8f4e12ff77
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp
@@ -0,0 +1,56 @@
+//===-- DWARFDebugRanges.cpp ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugRanges.h"
+#include "DWARFUnit.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
+
+using namespace lldb_private;
+using namespace lldb_private::plugin::dwarf;
+
+DWARFDebugRanges::DWARFDebugRanges() : m_range_map() {}
+
+void DWARFDebugRanges::Extract(DWARFContext &context) {
+ llvm::DWARFDataExtractor extractor =
+ context.getOrLoadRangesData().GetAsLLVMDWARF();
+ llvm::DWARFDebugRangeList extracted_list;
+ uint64_t current_offset = 0;
+ auto extract_next_list = [&] {
+ if (auto error = extracted_list.extract(extractor, &current_offset)) {
+ consumeError(std::move(error));
+ return false;
+ }
+ return true;
+ };
+
+ uint64_t previous_offset = current_offset;
+ while (extractor.isValidOffset(current_offset) && extract_next_list()) {
+ DWARFRangeList &lldb_range_list = m_range_map[previous_offset];
+ lldb_range_list.Reserve(extracted_list.getEntries().size());
+ for (auto &range : extracted_list.getEntries())
+ lldb_range_list.Append(range.StartAddress,
+ range.EndAddress - range.StartAddress);
+ lldb_range_list.Sort();
+ previous_offset = current_offset;
+ }
+}
+
+DWARFRangeList
+DWARFDebugRanges::FindRanges(const DWARFUnit *cu,
+ dw_offset_t debug_ranges_offset) const {
+ dw_addr_t debug_ranges_address = cu->GetRangesBase() + debug_ranges_offset;
+ auto pos = m_range_map.find(debug_ranges_address);
+ DWARFRangeList ans =
+ pos == m_range_map.end() ? DWARFRangeList() : pos->second;
+
+ // All DW_AT_ranges are relative to the base address of the compile
+ // unit. We add the compile unit base address to make sure all the
+ // addresses are properly fixed up.
+ ans.Slide(cu->GetBaseAddress());
+ return ans;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h
new file mode 100644
index 000000000000..a04fcf59d5bf
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h
@@ -0,0 +1,34 @@
+//===-- DWARFDebugRanges.h --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGRANGES_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGRANGES_H
+
+#include "lldb/Core/dwarf.h"
+#include <map>
+
+namespace lldb_private::plugin {
+namespace dwarf {
+class DWARFUnit;
+class DWARFContext;
+
+class DWARFDebugRanges {
+public:
+ DWARFDebugRanges();
+
+ void Extract(DWARFContext &context);
+ DWARFRangeList FindRanges(const DWARFUnit *cu,
+ dw_offset_t debug_ranges_offset) const;
+
+protected:
+ std::map<dw_offset_t, DWARFRangeList> m_range_map;
+};
+} // namespace dwarf
+} // namespace lldb_private::plugin
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGRANGES_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp
new file mode 100644
index 000000000000..f759cb8fae61
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp
@@ -0,0 +1,89 @@
+//===-- DWARFDeclContext.cpp ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDeclContext.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace lldb_private::dwarf;
+using namespace lldb_private::plugin::dwarf;
+
+const char *DWARFDeclContext::Entry::GetName() const {
+ if (name != nullptr)
+ return name;
+ if (tag == DW_TAG_namespace)
+ return "(anonymous namespace)";
+ if (tag == DW_TAG_class_type)
+ return "(anonymous class)";
+ if (tag == DW_TAG_structure_type)
+ return "(anonymous struct)";
+ if (tag == DW_TAG_union_type)
+ return "(anonymous union)";
+ return "(anonymous)";
+}
+
+const char *DWARFDeclContext::GetQualifiedName() const {
+ if (m_qualified_name.empty()) {
+ // The declaration context array for a class named "foo" in namespace
+ // "a::b::c" will be something like:
+ // [0] DW_TAG_class_type "foo"
+ // [1] DW_TAG_namespace "c"
+ // [2] DW_TAG_namespace "b"
+ // [3] DW_TAG_namespace "a"
+ if (!m_entries.empty()) {
+ if (m_entries.size() == 1) {
+ if (m_entries[0].name) {
+ m_qualified_name.append("::");
+ m_qualified_name.append(m_entries[0].name);
+ }
+ } else {
+ llvm::raw_string_ostream string_stream(m_qualified_name);
+ llvm::interleave(
+ llvm::reverse(m_entries), string_stream,
+ [&](auto entry) { string_stream << entry.GetName(); }, "::");
+ }
+ }
+ }
+ if (m_qualified_name.empty())
+ return nullptr;
+ return m_qualified_name.c_str();
+}
+
+bool DWARFDeclContext::operator==(const DWARFDeclContext &rhs) const {
+ if (m_entries.size() != rhs.m_entries.size())
+ return false;
+
+ collection::const_iterator pos;
+ collection::const_iterator begin = m_entries.begin();
+ collection::const_iterator end = m_entries.end();
+
+ collection::const_iterator rhs_pos;
+ collection::const_iterator rhs_begin = rhs.m_entries.begin();
+ // The two entry arrays have the same size
+
+ // First compare the tags before we do expensive name compares
+ for (pos = begin, rhs_pos = rhs_begin; pos != end; ++pos, ++rhs_pos) {
+ if (pos->tag != rhs_pos->tag) {
+ // Check for DW_TAG_structure_type and DW_TAG_class_type as they are
+ // often used interchangeably in GCC
+ if (pos->tag == DW_TAG_structure_type &&
+ rhs_pos->tag == DW_TAG_class_type)
+ continue;
+ if (pos->tag == DW_TAG_class_type &&
+ rhs_pos->tag == DW_TAG_structure_type)
+ continue;
+ return false;
+ }
+ }
+ // The tags all match, now compare the names
+ for (pos = begin, rhs_pos = rhs_begin; pos != end; ++pos, ++rhs_pos) {
+ if (!pos->NameMatches(*rhs_pos))
+ return false;
+ }
+ // All tags and names match
+ return true;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h
new file mode 100644
index 000000000000..b563d1c4417b
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h
@@ -0,0 +1,110 @@
+//===-- DWARFDeclContext.h --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDECLCONTEXT_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDECLCONTEXT_H
+
+#include "DWARFDefines.h"
+#include "lldb/Utility/ConstString.h"
+#include "llvm/ADT/StringExtras.h"
+
+#include <cassert>
+#include <string>
+#include <vector>
+
+namespace lldb_private::plugin {
+namespace dwarf {
+// DWARFDeclContext
+//
+// A class that represents a declaration context all the way down to a
+// DIE. This is useful when trying to find a DIE in one DWARF to a DIE
+// in another DWARF file.
+
+class DWARFDeclContext {
+public:
+ struct Entry {
+ Entry() = default;
+ Entry(dw_tag_t t, const char *n) : tag(t), name(n) {}
+
+ bool NameMatches(const Entry &rhs) const {
+ if (name == rhs.name)
+ return true;
+ else if (name && rhs.name)
+ return strcmp(name, rhs.name) == 0;
+ return false;
+ }
+
+ /// Returns the name of this entry if it has one, or the appropriate
+ /// "anonymous {namespace, class, struct, union}".
+ const char *GetName() const;
+
+ // Test operator
+ explicit operator bool() const { return tag != 0; }
+
+ dw_tag_t tag = llvm::dwarf::DW_TAG_null;
+ const char *name = nullptr;
+ };
+
+ DWARFDeclContext() : m_entries() {}
+
+ DWARFDeclContext(llvm::ArrayRef<Entry> entries) {
+ llvm::append_range(m_entries, entries);
+ }
+
+ void AppendDeclContext(dw_tag_t tag, const char *name) {
+ m_entries.push_back(Entry(tag, name));
+ }
+
+ bool operator==(const DWARFDeclContext &rhs) const;
+ bool operator!=(const DWARFDeclContext &rhs) const { return !(*this == rhs); }
+
+ uint32_t GetSize() const { return m_entries.size(); }
+
+ Entry &operator[](uint32_t idx) {
+ assert(idx < m_entries.size() && "invalid index");
+ return m_entries[idx];
+ }
+
+ const Entry &operator[](uint32_t idx) const {
+ assert(idx < m_entries.size() && "invalid index");
+ return m_entries[idx];
+ }
+
+ const char *GetQualifiedName() const;
+
+ // Same as GetQualifiedName, but the life time of the returned string will
+ // be that of the LLDB session.
+ ConstString GetQualifiedNameAsConstString() const {
+ return ConstString(GetQualifiedName());
+ }
+
+ void Clear() {
+ m_entries.clear();
+ m_qualified_name.clear();
+ }
+
+ friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+ const DWARFDeclContext &ctx) {
+ OS << "DWARFDeclContext{";
+ llvm::ListSeparator LS;
+ for (const Entry &e : ctx.m_entries) {
+ OS << LS << "{" << DW_TAG_value_to_name(e.tag) << ", " << e.GetName()
+ << "}";
+ }
+ return OS << "}";
+ }
+
+protected:
+ typedef std::vector<Entry> collection;
+ collection m_entries;
+ mutable std::string m_qualified_name;
+};
+} // namespace dwarf
+} // namespace lldb_private::plugin
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDECLCONTEXT_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp
new file mode 100644
index 000000000000..2fb0c224bf8e
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp
@@ -0,0 +1,37 @@
+//===-- DWARFDefines.cpp --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDefines.h"
+#include "lldb/Utility/ConstString.h"
+#include <cstdio>
+#include <cstring>
+#include <string>
+
+namespace lldb_private::plugin {
+namespace dwarf {
+
+llvm::StringRef DW_TAG_value_to_name(dw_tag_t tag) {
+ static constexpr llvm::StringLiteral s_unknown_tag_name("<unknown DW_TAG>");
+ if (llvm::StringRef tag_name = llvm::dwarf::TagString(tag); !tag_name.empty())
+ return tag_name;
+
+ return s_unknown_tag_name;
+}
+
+const char *DW_OP_value_to_name(uint32_t val) {
+ static char invalid[100];
+ llvm::StringRef llvmstr = llvm::dwarf::OperationEncodingString(val);
+ if (llvmstr.empty()) {
+ snprintf(invalid, sizeof(invalid), "Unknown DW_OP constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr.data();
+}
+
+} // namespace dwarf
+} // namespace lldb_private::plugin
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.h
new file mode 100644
index 000000000000..be81cb0f5df1
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.h
@@ -0,0 +1,25 @@
+//===-- DWARFDefines.h ------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEFINES_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEFINES_H
+
+#include "lldb/Core/dwarf.h"
+#include <cstdint>
+
+namespace lldb_private::plugin {
+namespace dwarf {
+
+llvm::StringRef DW_TAG_value_to_name(dw_tag_t tag);
+
+const char *DW_OP_value_to_name(uint32_t val);
+
+} // namespace dwarf
+} // namespace lldb_private::plugin
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEFINES_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
new file mode 100644
index 000000000000..e1f73f1997e3
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
@@ -0,0 +1,647 @@
+//===-- DWARFFormValue.cpp ------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <cassert>
+#include <optional>
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/dwarf.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Utility/Stream.h"
+
+#include "DWARFDebugInfo.h"
+#include "DWARFFormValue.h"
+#include "DWARFUnit.h"
+
+using namespace lldb_private;
+using namespace lldb_private::dwarf;
+using namespace lldb_private::plugin::dwarf;
+
+void DWARFFormValue::Clear() {
+ m_unit = nullptr;
+ m_form = dw_form_t(0);
+ m_value = ValueTypeTag();
+}
+
+bool DWARFFormValue::ExtractValue(const DWARFDataExtractor &data,
+ lldb::offset_t *offset_ptr) {
+ if (m_form == DW_FORM_implicit_const)
+ return true;
+
+ bool indirect = false;
+ bool is_block = false;
+ m_value.data = nullptr;
+ uint8_t ref_addr_size;
+ // Read the value for the form into value and follow and DW_FORM_indirect
+ // instances we run into
+ do {
+ indirect = false;
+ switch (m_form) {
+ case DW_FORM_addr:
+ assert(m_unit);
+ m_value.value.uval =
+ data.GetMaxU64(offset_ptr, DWARFUnit::GetAddressByteSize(m_unit));
+ break;
+ case DW_FORM_block1:
+ m_value.value.uval = data.GetU8(offset_ptr);
+ is_block = true;
+ break;
+ case DW_FORM_block2:
+ m_value.value.uval = data.GetU16(offset_ptr);
+ is_block = true;
+ break;
+ case DW_FORM_block4:
+ m_value.value.uval = data.GetU32(offset_ptr);
+ is_block = true;
+ break;
+ case DW_FORM_data16:
+ m_value.value.uval = 16;
+ is_block = true;
+ break;
+ case DW_FORM_exprloc:
+ case DW_FORM_block:
+ m_value.value.uval = data.GetULEB128(offset_ptr);
+ is_block = true;
+ break;
+ case DW_FORM_string:
+ m_value.value.cstr = data.GetCStr(offset_ptr);
+ break;
+ case DW_FORM_sdata:
+ m_value.value.sval = data.GetSLEB128(offset_ptr);
+ break;
+ case DW_FORM_strp:
+ case DW_FORM_line_strp:
+ case DW_FORM_sec_offset:
+ m_value.value.uval = data.GetMaxU64(offset_ptr, 4);
+ break;
+ case DW_FORM_addrx1:
+ case DW_FORM_strx1:
+ case DW_FORM_ref1:
+ case DW_FORM_data1:
+ case DW_FORM_flag:
+ m_value.value.uval = data.GetU8(offset_ptr);
+ break;
+ case DW_FORM_addrx2:
+ case DW_FORM_strx2:
+ case DW_FORM_ref2:
+ case DW_FORM_data2:
+ m_value.value.uval = data.GetU16(offset_ptr);
+ break;
+ case DW_FORM_addrx3:
+ case DW_FORM_strx3:
+ m_value.value.uval = data.GetMaxU64(offset_ptr, 3);
+ break;
+ case DW_FORM_addrx4:
+ case DW_FORM_strx4:
+ case DW_FORM_ref4:
+ case DW_FORM_data4:
+ m_value.value.uval = data.GetU32(offset_ptr);
+ break;
+ case DW_FORM_data8:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_sig8:
+ m_value.value.uval = data.GetU64(offset_ptr);
+ break;
+ case DW_FORM_addrx:
+ case DW_FORM_loclistx:
+ case DW_FORM_rnglistx:
+ case DW_FORM_strx:
+ case DW_FORM_udata:
+ case DW_FORM_ref_udata:
+ case DW_FORM_GNU_str_index:
+ case DW_FORM_GNU_addr_index:
+ m_value.value.uval = data.GetULEB128(offset_ptr);
+ break;
+ case DW_FORM_ref_addr:
+ assert(m_unit);
+ if (m_unit->GetVersion() <= 2)
+ ref_addr_size = m_unit->GetAddressByteSize();
+ else
+ ref_addr_size = 4;
+ m_value.value.uval = data.GetMaxU64(offset_ptr, ref_addr_size);
+ break;
+ case DW_FORM_indirect:
+ m_form = static_cast<dw_form_t>(data.GetULEB128(offset_ptr));
+ indirect = true;
+ break;
+ case DW_FORM_flag_present:
+ m_value.value.uval = 1;
+ break;
+ default:
+ return false;
+ }
+ } while (indirect);
+
+ if (is_block) {
+ m_value.data = data.PeekData(*offset_ptr, m_value.value.uval);
+ if (m_value.data != nullptr) {
+ *offset_ptr += m_value.value.uval;
+ }
+ }
+
+ return true;
+}
+
+struct FormSize {
+ uint8_t valid:1, size:7;
+};
+static FormSize g_form_sizes[] = {
+ {0, 0}, // 0x00 unused
+ {0, 0}, // 0x01 DW_FORM_addr
+ {0, 0}, // 0x02 unused
+ {0, 0}, // 0x03 DW_FORM_block2
+ {0, 0}, // 0x04 DW_FORM_block4
+ {1, 2}, // 0x05 DW_FORM_data2
+ {1, 4}, // 0x06 DW_FORM_data4
+ {1, 8}, // 0x07 DW_FORM_data8
+ {0, 0}, // 0x08 DW_FORM_string
+ {0, 0}, // 0x09 DW_FORM_block
+ {0, 0}, // 0x0a DW_FORM_block1
+ {1, 1}, // 0x0b DW_FORM_data1
+ {1, 1}, // 0x0c DW_FORM_flag
+ {0, 0}, // 0x0d DW_FORM_sdata
+ {1, 4}, // 0x0e DW_FORM_strp
+ {0, 0}, // 0x0f DW_FORM_udata
+ {0, 0}, // 0x10 DW_FORM_ref_addr (addr size for DWARF2 and earlier, 4 bytes
+ // for DWARF32, 8 bytes for DWARF32 in DWARF 3 and later
+ {1, 1}, // 0x11 DW_FORM_ref1
+ {1, 2}, // 0x12 DW_FORM_ref2
+ {1, 4}, // 0x13 DW_FORM_ref4
+ {1, 8}, // 0x14 DW_FORM_ref8
+ {0, 0}, // 0x15 DW_FORM_ref_udata
+ {0, 0}, // 0x16 DW_FORM_indirect
+ {1, 4}, // 0x17 DW_FORM_sec_offset
+ {0, 0}, // 0x18 DW_FORM_exprloc
+ {1, 0}, // 0x19 DW_FORM_flag_present
+ {0, 0}, // 0x1a DW_FORM_strx (ULEB128)
+ {0, 0}, // 0x1b DW_FORM_addrx (ULEB128)
+ {1, 4}, // 0x1c DW_FORM_ref_sup4
+ {0, 0}, // 0x1d DW_FORM_strp_sup (4 bytes for DWARF32, 8 bytes for DWARF64)
+ {1, 16}, // 0x1e DW_FORM_data16
+ {1, 4}, // 0x1f DW_FORM_line_strp
+ {1, 8}, // 0x20 DW_FORM_ref_sig8
+};
+
+std::optional<uint8_t> DWARFFormValue::GetFixedSize(dw_form_t form,
+ const DWARFUnit *u) {
+ if (form <= DW_FORM_ref_sig8 && g_form_sizes[form].valid)
+ return static_cast<uint8_t>(g_form_sizes[form].size);
+ if (form == DW_FORM_addr && u)
+ return u->GetAddressByteSize();
+ return std::nullopt;
+}
+
+std::optional<uint8_t> DWARFFormValue::GetFixedSize() const {
+ return GetFixedSize(m_form, m_unit);
+}
+
+bool DWARFFormValue::SkipValue(const DWARFDataExtractor &debug_info_data,
+ lldb::offset_t *offset_ptr) const {
+ return DWARFFormValue::SkipValue(m_form, debug_info_data, offset_ptr, m_unit);
+}
+
+bool DWARFFormValue::SkipValue(dw_form_t form,
+ const DWARFDataExtractor &debug_info_data,
+ lldb::offset_t *offset_ptr,
+ const DWARFUnit *unit) {
+ uint8_t ref_addr_size;
+ switch (form) {
+ // Blocks if inlined data that have a length field and the data bytes inlined
+ // in the .debug_info
+ case DW_FORM_exprloc:
+ case DW_FORM_block: {
+ uint64_t size = debug_info_data.GetULEB128(offset_ptr);
+ *offset_ptr += size;
+ }
+ return true;
+ case DW_FORM_block1: {
+ uint8_t size = debug_info_data.GetU8(offset_ptr);
+ *offset_ptr += size;
+ }
+ return true;
+ case DW_FORM_block2: {
+ uint16_t size = debug_info_data.GetU16(offset_ptr);
+ *offset_ptr += size;
+ }
+ return true;
+ case DW_FORM_block4: {
+ uint32_t size = debug_info_data.GetU32(offset_ptr);
+ *offset_ptr += size;
+ }
+ return true;
+
+ // Inlined NULL terminated C-strings
+ case DW_FORM_string:
+ debug_info_data.GetCStr(offset_ptr);
+ return true;
+
+ // Compile unit address sized values
+ case DW_FORM_addr:
+ *offset_ptr += DWARFUnit::GetAddressByteSize(unit);
+ return true;
+
+ case DW_FORM_ref_addr:
+ ref_addr_size = 4;
+ assert(unit); // Unit must be valid for DW_FORM_ref_addr objects or we will
+ // get this wrong
+ if (unit->GetVersion() <= 2)
+ ref_addr_size = unit->GetAddressByteSize();
+ else
+ ref_addr_size = 4;
+ *offset_ptr += ref_addr_size;
+ return true;
+
+ // 0 bytes values (implied from DW_FORM)
+ case DW_FORM_flag_present:
+ case DW_FORM_implicit_const:
+ return true;
+
+ // 1 byte values
+ case DW_FORM_addrx1:
+ case DW_FORM_data1:
+ case DW_FORM_flag:
+ case DW_FORM_ref1:
+ case DW_FORM_strx1:
+ *offset_ptr += 1;
+ return true;
+
+ // 2 byte values
+ case DW_FORM_addrx2:
+ case DW_FORM_data2:
+ case DW_FORM_ref2:
+ case DW_FORM_strx2:
+ *offset_ptr += 2;
+ return true;
+
+ // 3 byte values
+ case DW_FORM_addrx3:
+ case DW_FORM_strx3:
+ *offset_ptr += 3;
+ return true;
+
+ // 32 bit for DWARF 32, 64 for DWARF 64
+ case DW_FORM_sec_offset:
+ case DW_FORM_strp:
+ case DW_FORM_line_strp:
+ *offset_ptr += 4;
+ return true;
+
+ // 4 byte values
+ case DW_FORM_addrx4:
+ case DW_FORM_data4:
+ case DW_FORM_ref4:
+ case DW_FORM_strx4:
+ *offset_ptr += 4;
+ return true;
+
+ // 8 byte values
+ case DW_FORM_data8:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_sig8:
+ *offset_ptr += 8;
+ return true;
+
+ // signed or unsigned LEB 128 values
+ case DW_FORM_addrx:
+ case DW_FORM_loclistx:
+ case DW_FORM_rnglistx:
+ case DW_FORM_sdata:
+ case DW_FORM_udata:
+ case DW_FORM_ref_udata:
+ case DW_FORM_GNU_addr_index:
+ case DW_FORM_GNU_str_index:
+ case DW_FORM_strx:
+ debug_info_data.Skip_LEB128(offset_ptr);
+ return true;
+
+ case DW_FORM_indirect: {
+ auto indirect_form =
+ static_cast<dw_form_t>(debug_info_data.GetULEB128(offset_ptr));
+ return DWARFFormValue::SkipValue(indirect_form, debug_info_data,
+ offset_ptr, unit);
+ }
+
+ default:
+ break;
+ }
+ return false;
+}
+
+void DWARFFormValue::Dump(Stream &s) const {
+ uint64_t uvalue = Unsigned();
+ bool unit_relative_offset = false;
+
+ switch (m_form) {
+ case DW_FORM_addr:
+ DumpAddress(s.AsRawOstream(), uvalue, sizeof(uint64_t));
+ break;
+ case DW_FORM_flag:
+ case DW_FORM_data1:
+ s.PutHex8(uvalue);
+ break;
+ case DW_FORM_data2:
+ s.PutHex16(uvalue);
+ break;
+ case DW_FORM_sec_offset:
+ case DW_FORM_data4:
+ s.PutHex32(uvalue);
+ break;
+ case DW_FORM_ref_sig8:
+ case DW_FORM_data8:
+ s.PutHex64(uvalue);
+ break;
+ case DW_FORM_string:
+ s.QuotedCString(AsCString());
+ break;
+ case DW_FORM_exprloc:
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ if (uvalue > 0) {
+ switch (m_form) {
+ case DW_FORM_exprloc:
+ case DW_FORM_block:
+ s.Printf("<0x%" PRIx64 "> ", uvalue);
+ break;
+ case DW_FORM_block1:
+ s.Printf("<0x%2.2x> ", (uint8_t)uvalue);
+ break;
+ case DW_FORM_block2:
+ s.Printf("<0x%4.4x> ", (uint16_t)uvalue);
+ break;
+ case DW_FORM_block4:
+ s.Printf("<0x%8.8x> ", (uint32_t)uvalue);
+ break;
+ default:
+ break;
+ }
+
+ const uint8_t *data_ptr = m_value.data;
+ if (data_ptr) {
+ const uint8_t *end_data_ptr =
+ data_ptr + uvalue; // uvalue contains size of block
+ while (data_ptr < end_data_ptr) {
+ s.Printf("%2.2x ", *data_ptr);
+ ++data_ptr;
+ }
+ } else
+ s.PutCString("NULL");
+ }
+ break;
+
+ case DW_FORM_sdata:
+ s.PutSLEB128(uvalue);
+ break;
+ case DW_FORM_udata:
+ s.PutULEB128(uvalue);
+ break;
+ case DW_FORM_strp:
+ case DW_FORM_line_strp: {
+ const char *dbg_str = AsCString();
+ if (dbg_str) {
+ s.QuotedCString(dbg_str);
+ } else {
+ s.PutHex32(uvalue);
+ }
+ } break;
+
+ case DW_FORM_ref_addr: {
+ assert(m_unit); // Unit must be valid for DW_FORM_ref_addr objects or we
+ // will get this wrong
+ if (m_unit->GetVersion() <= 2)
+ DumpAddress(s.AsRawOstream(), uvalue, sizeof(uint64_t) * 2);
+ else
+ DumpAddress(s.AsRawOstream(), uvalue,
+ 4 * 2); // 4 for DWARF32, 8 for DWARF64, but we don't
+ // support DWARF64 yet
+ break;
+ }
+ case DW_FORM_ref1:
+ unit_relative_offset = true;
+ break;
+ case DW_FORM_ref2:
+ unit_relative_offset = true;
+ break;
+ case DW_FORM_ref4:
+ unit_relative_offset = true;
+ break;
+ case DW_FORM_ref8:
+ unit_relative_offset = true;
+ break;
+ case DW_FORM_ref_udata:
+ unit_relative_offset = true;
+ break;
+
+ // All DW_FORM_indirect attributes should be resolved prior to calling this
+ // function
+ case DW_FORM_indirect:
+ s.PutCString("DW_FORM_indirect");
+ break;
+ case DW_FORM_flag_present:
+ break;
+ default:
+ s.Printf("DW_FORM(0x%4.4x)", m_form);
+ break;
+ }
+
+ if (unit_relative_offset) {
+ assert(m_unit); // Unit must be valid for DW_FORM_ref forms that are compile
+ // unit relative or we will get this wrong
+ s.Printf("{0x%8.8" PRIx64 "}", uvalue + m_unit->GetOffset());
+ }
+}
+
+const char *DWARFFormValue::AsCString() const {
+ DWARFContext &context = m_unit->GetSymbolFileDWARF().GetDWARFContext();
+
+ if (m_form == DW_FORM_string)
+ return m_value.value.cstr;
+ if (m_form == DW_FORM_strp)
+ return context.getOrLoadStrData().PeekCStr(m_value.value.uval);
+
+ if (m_form == DW_FORM_GNU_str_index || m_form == DW_FORM_strx ||
+ m_form == DW_FORM_strx1 || m_form == DW_FORM_strx2 ||
+ m_form == DW_FORM_strx3 || m_form == DW_FORM_strx4) {
+
+ std::optional<uint64_t> offset =
+ m_unit->GetStringOffsetSectionItem(m_value.value.uval);
+ if (!offset)
+ return nullptr;
+ return context.getOrLoadStrData().PeekCStr(*offset);
+ }
+
+ if (m_form == DW_FORM_line_strp)
+ return context.getOrLoadLineStrData().PeekCStr(m_value.value.uval);
+
+ return nullptr;
+}
+
+dw_addr_t DWARFFormValue::Address() const {
+ SymbolFileDWARF &symbol_file = m_unit->GetSymbolFileDWARF();
+
+ if (m_form == DW_FORM_addr)
+ return Unsigned();
+
+ assert(m_unit);
+ assert(m_form == DW_FORM_GNU_addr_index || m_form == DW_FORM_addrx ||
+ m_form == DW_FORM_addrx1 || m_form == DW_FORM_addrx2 ||
+ m_form == DW_FORM_addrx3 || m_form == DW_FORM_addrx4);
+
+ uint32_t index_size = m_unit->GetAddressByteSize();
+ dw_offset_t addr_base = m_unit->GetAddrBase();
+ lldb::offset_t offset = addr_base + m_value.value.uval * index_size;
+ return symbol_file.GetDWARFContext().getOrLoadAddrData().GetMaxU64(
+ &offset, index_size);
+}
+
+std::pair<DWARFUnit *, uint64_t>
+DWARFFormValue::ReferencedUnitAndOffset() const {
+ uint64_t value = m_value.value.uval;
+ 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_unit); // Unit must be valid for DW_FORM_ref forms that are compile
+ // unit relative or we will get this wrong
+ value += m_unit->GetOffset();
+ if (!m_unit->ContainsDIEOffset(value)) {
+ m_unit->GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(
+ "DW_FORM_ref* DIE reference {0:x16} is outside of its CU", value);
+ return {nullptr, 0};
+ }
+ return {const_cast<DWARFUnit *>(m_unit), value};
+
+ case DW_FORM_ref_addr: {
+ DWARFUnit *ref_cu =
+ m_unit->GetSymbolFileDWARF().DebugInfo().GetUnitContainingDIEOffset(
+ DIERef::Section::DebugInfo, value);
+ if (!ref_cu) {
+ m_unit->GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(
+ "DW_FORM_ref_addr DIE reference {0:x16} has no matching CU", value);
+ return {nullptr, 0};
+ }
+ return {ref_cu, value};
+ }
+
+ case DW_FORM_ref_sig8: {
+ DWARFTypeUnit *tu =
+ m_unit->GetSymbolFileDWARF().DebugInfo().GetTypeUnitForHash(value);
+ if (!tu)
+ return {nullptr, 0};
+ return {tu, tu->GetTypeOffset()};
+ }
+
+ default:
+ return {nullptr, 0};
+ }
+}
+
+DWARFDIE DWARFFormValue::Reference() const {
+ auto [unit, offset] = ReferencedUnitAndOffset();
+ return unit ? unit->GetDIE(offset) : DWARFDIE();
+}
+
+uint64_t DWARFFormValue::Reference(dw_offset_t base_offset) const {
+ uint64_t value = m_value.value.uval;
+ switch (m_form) {
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_udata:
+ return value + base_offset;
+
+ case DW_FORM_ref_addr:
+ case DW_FORM_ref_sig8:
+ case DW_FORM_GNU_ref_alt:
+ return value;
+
+ default:
+ return DW_INVALID_OFFSET;
+ }
+}
+
+const uint8_t *DWARFFormValue::BlockData() const { return m_value.data; }
+
+bool DWARFFormValue::IsBlockForm(const dw_form_t form) {
+ switch (form) {
+ case DW_FORM_exprloc:
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ return true;
+ default:
+ return false;
+ }
+ llvm_unreachable("All cases handled above!");
+}
+
+bool DWARFFormValue::IsDataForm(const dw_form_t form) {
+ switch (form) {
+ case DW_FORM_sdata:
+ case DW_FORM_udata:
+ case DW_FORM_data1:
+ case DW_FORM_data2:
+ case DW_FORM_data4:
+ case DW_FORM_data8:
+ return true;
+ default:
+ return false;
+ }
+ llvm_unreachable("All cases handled above!");
+}
+
+bool DWARFFormValue::FormIsSupported(dw_form_t form) {
+ switch (form) {
+ case DW_FORM_addr:
+ case DW_FORM_addrx:
+ case DW_FORM_loclistx:
+ case DW_FORM_rnglistx:
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ case DW_FORM_data2:
+ case DW_FORM_data4:
+ case DW_FORM_data8:
+ case DW_FORM_string:
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ case DW_FORM_data1:
+ case DW_FORM_flag:
+ case DW_FORM_sdata:
+ case DW_FORM_strp:
+ case DW_FORM_line_strp:
+ case DW_FORM_strx:
+ case DW_FORM_strx1:
+ case DW_FORM_strx2:
+ case DW_FORM_strx3:
+ case DW_FORM_strx4:
+ case DW_FORM_udata:
+ case DW_FORM_ref_addr:
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_udata:
+ case DW_FORM_indirect:
+ case DW_FORM_sec_offset:
+ case DW_FORM_exprloc:
+ case DW_FORM_flag_present:
+ case DW_FORM_ref_sig8:
+ case DW_FORM_GNU_str_index:
+ case DW_FORM_GNU_addr_index:
+ case DW_FORM_implicit_const:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h
new file mode 100644
index 000000000000..fdd5b3c278a4
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h
@@ -0,0 +1,99 @@
+//===-- DWARFFormValue.h ----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFFORMVALUE_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFFORMVALUE_H
+
+#include "DWARFDataExtractor.h"
+#include <cstddef>
+#include <optional>
+
+namespace lldb_private::plugin {
+namespace dwarf {
+class DWARFUnit;
+class SymbolFileDWARF;
+class DWARFDIE;
+
+class DWARFFormValue {
+public:
+ typedef struct ValueTypeTag {
+ ValueTypeTag() : value() { value.uval = 0; }
+
+ union {
+ uint64_t uval;
+ int64_t sval;
+ const char *cstr;
+ } value;
+ const uint8_t *data = nullptr;
+ } ValueType;
+
+ enum {
+ eValueTypeInvalid = 0,
+ eValueTypeUnsigned,
+ eValueTypeSigned,
+ eValueTypeCStr,
+ eValueTypeBlock
+ };
+
+ DWARFFormValue() = default;
+ DWARFFormValue(const DWARFUnit *unit) : m_unit(unit) {}
+ DWARFFormValue(const DWARFUnit *unit, dw_form_t form)
+ : m_unit(unit), m_form(form) {}
+ const DWARFUnit *GetUnit() const { return m_unit; }
+ void SetUnit(const DWARFUnit *unit) { m_unit = unit; }
+ dw_form_t Form() const { return m_form; }
+ dw_form_t &FormRef() { return m_form; }
+ void SetForm(dw_form_t form) { m_form = form; }
+ const ValueType &Value() const { return m_value; }
+ ValueType &ValueRef() { return m_value; }
+ void SetValue(const ValueType &val) { m_value = val; }
+
+ void Dump(Stream &s) const;
+ bool ExtractValue(const DWARFDataExtractor &data, lldb::offset_t *offset_ptr);
+ const uint8_t *BlockData() const;
+ static std::optional<uint8_t> GetFixedSize(dw_form_t form,
+ const DWARFUnit *u);
+ std::optional<uint8_t> GetFixedSize() const;
+ DWARFDIE Reference() const;
+
+ /// If this is a reference to another DIE, return the corresponding DWARFUnit
+ /// and DIE offset such that Unit->GetDIE(offset) produces the desired DIE.
+ /// Otherwise, a nullptr and unspecified offset are returned.
+ std::pair<DWARFUnit *, uint64_t> ReferencedUnitAndOffset() const;
+
+ uint64_t Reference(dw_offset_t offset) const;
+ bool Boolean() const { return m_value.value.uval != 0; }
+ uint64_t Unsigned() const { return m_value.value.uval; }
+ void SetUnsigned(uint64_t uval) { m_value.value.uval = uval; }
+ int64_t Signed() const { return m_value.value.sval; }
+ void SetSigned(int64_t sval) { m_value.value.sval = sval; }
+ const char *AsCString() const;
+ dw_addr_t Address() const;
+ bool IsValid() const { return m_form != 0; }
+ bool SkipValue(const DWARFDataExtractor &debug_info_data,
+ lldb::offset_t *offset_ptr) const;
+ static bool SkipValue(const dw_form_t form,
+ const DWARFDataExtractor &debug_info_data,
+ lldb::offset_t *offset_ptr, const DWARFUnit *unit);
+ static bool IsBlockForm(const dw_form_t form);
+ static bool IsDataForm(const dw_form_t form);
+ static int Compare(const DWARFFormValue &a, const DWARFFormValue &b);
+ void Clear();
+ static bool FormIsSupported(dw_form_t form);
+
+protected:
+ // Compile unit where m_value was located.
+ // It may be different from compile unit where m_value refers to.
+ const DWARFUnit *m_unit = nullptr; // Unit for this form
+ dw_form_t m_form = dw_form_t(0); // Form for this value
+ ValueType m_value; // Contains all data for the form
+};
+} // namespace dwarf
+} // namespace lldb_private::plugin
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFFORMVALUE_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp
new file mode 100644
index 000000000000..eafddbad03f5
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp
@@ -0,0 +1,128 @@
+//===-- DWARFIndex.cpp ----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/SymbolFile/DWARF/DWARFIndex.h"
+#include "DWARFDebugInfoEntry.h"
+#include "DWARFDeclContext.h"
+#include "Plugins/Language/ObjC/ObjCLanguage.h"
+#include "Plugins/SymbolFile/DWARF/DWARFDIE.h"
+#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
+
+#include "lldb/Core/Mangled.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Target/Language.h"
+
+using namespace lldb_private;
+using namespace lldb;
+using namespace lldb_private::plugin::dwarf;
+
+DWARFIndex::~DWARFIndex() = default;
+
+bool DWARFIndex::ProcessFunctionDIE(
+ const Module::LookupInfo &lookup_info, DWARFDIE die,
+ const CompilerDeclContext &parent_decl_ctx,
+ llvm::function_ref<bool(DWARFDIE die)> callback) {
+ llvm::StringRef name = lookup_info.GetLookupName().GetStringRef();
+ FunctionNameType name_type_mask = lookup_info.GetNameTypeMask();
+
+ if (!(name_type_mask & eFunctionNameTypeFull)) {
+ ConstString name_to_match_against;
+ if (const char *mangled_die_name = die.GetMangledName()) {
+ name_to_match_against = ConstString(mangled_die_name);
+ } else {
+ SymbolFileDWARF *symbols = die.GetDWARF();
+ if (ConstString demangled_die_name =
+ symbols->ConstructFunctionDemangledName(die))
+ name_to_match_against = demangled_die_name;
+ }
+
+ if (!lookup_info.NameMatchesLookupInfo(name_to_match_against,
+ lookup_info.GetLanguageType()))
+ return true;
+ }
+
+ // Exit early if we're searching exclusively for methods or selectors and
+ // we have a context specified (no methods in namespaces).
+ uint32_t looking_for_nonmethods =
+ name_type_mask & ~(eFunctionNameTypeMethod | eFunctionNameTypeSelector);
+ if (!looking_for_nonmethods && parent_decl_ctx.IsValid())
+ return true;
+
+ // Otherwise, we need to also check that the context matches. If it does not
+ // match, we do nothing.
+ if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx, die))
+ return true;
+
+ // In case of a full match, we just insert everything we find.
+ if (name_type_mask & eFunctionNameTypeFull && die.GetMangledName() == name)
+ return callback(die);
+
+ // If looking for ObjC selectors, we need to also check if the name is a
+ // possible selector.
+ if (name_type_mask & eFunctionNameTypeSelector &&
+ ObjCLanguage::IsPossibleObjCMethodName(die.GetName()))
+ return callback(die);
+
+ bool looking_for_methods = name_type_mask & lldb::eFunctionNameTypeMethod;
+ bool looking_for_functions = name_type_mask & lldb::eFunctionNameTypeBase;
+ if (looking_for_methods || looking_for_functions) {
+ // If we're looking for either methods or functions, we definitely want this
+ // die. Otherwise, only keep it if the die type matches what we are
+ // searching for.
+ if ((looking_for_methods && looking_for_functions) ||
+ looking_for_methods == die.IsMethod())
+ return callback(die);
+ }
+
+ return true;
+}
+
+DWARFIndex::DIERefCallbackImpl::DIERefCallbackImpl(
+ const DWARFIndex &index, llvm::function_ref<bool(DWARFDIE die)> callback,
+ llvm::StringRef name)
+ : m_index(index),
+ m_dwarf(*llvm::cast<SymbolFileDWARF>(
+ index.m_module.GetSymbolFile()->GetBackingSymbolFile())),
+ m_callback(callback), m_name(name) {}
+
+bool DWARFIndex::DIERefCallbackImpl::operator()(DIERef ref) const {
+ if (DWARFDIE die = m_dwarf.GetDIE(ref))
+ return m_callback(die);
+ m_index.ReportInvalidDIERef(ref, m_name);
+ return true;
+}
+
+bool DWARFIndex::DIERefCallbackImpl::operator()(
+ const llvm::AppleAcceleratorTable::Entry &entry) const {
+ return this->operator()(DIERef(std::nullopt, DIERef::Section::DebugInfo,
+ *entry.getDIESectionOffset()));
+}
+
+void DWARFIndex::ReportInvalidDIERef(DIERef ref, llvm::StringRef name) const {
+ m_module.ReportErrorIfModifyDetected(
+ "the DWARF debug information has been modified (accelerator table had "
+ "bad die {0:x16} for '{1}')\n",
+ ref.die_offset(), name.str().c_str());
+}
+
+void DWARFIndex::GetFullyQualifiedType(
+ const DWARFDeclContext &context,
+ llvm::function_ref<bool(DWARFDIE die)> callback) {
+ GetTypes(context, [&](DWARFDIE die) {
+ return GetFullyQualifiedTypeImpl(context, die, callback);
+ });
+}
+
+bool DWARFIndex::GetFullyQualifiedTypeImpl(
+ const DWARFDeclContext &context, DWARFDIE die,
+ llvm::function_ref<bool(DWARFDIE die)> callback) {
+ DWARFDeclContext dwarf_decl_ctx = die.GetDWARFDeclContext();
+ if (dwarf_decl_ctx == context)
+ return callback(die);
+ return true;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h
new file mode 100644
index 000000000000..cb3ae8a06d78
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h
@@ -0,0 +1,122 @@
+//===-- DWARFIndex.h -------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFINDEX_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFINDEX_H
+
+#include "Plugins/SymbolFile/DWARF/DIERef.h"
+#include "Plugins/SymbolFile/DWARF/DWARFDIE.h"
+#include "Plugins/SymbolFile/DWARF/DWARFFormValue.h"
+#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
+
+#include "lldb/Core/Module.h"
+#include "lldb/Target/Statistics.h"
+
+namespace lldb_private::plugin {
+namespace dwarf {
+class DWARFDeclContext;
+class DWARFDIE;
+
+class DWARFIndex {
+public:
+ DWARFIndex(Module &module) : m_module(module) {}
+ virtual ~DWARFIndex();
+
+ virtual void Preload() = 0;
+
+ /// Finds global variables with the given base name. Any additional filtering
+ /// (e.g., to only retrieve variables from a given context) should be done by
+ /// the consumer.
+ virtual void
+ GetGlobalVariables(ConstString basename,
+ llvm::function_ref<bool(DWARFDIE die)> callback) = 0;
+
+ virtual void
+ GetGlobalVariables(const RegularExpression &regex,
+ llvm::function_ref<bool(DWARFDIE die)> callback) = 0;
+ /// \a cu must be the skeleton unit if possible, not GetNonSkeletonUnit().
+ virtual void
+ GetGlobalVariables(DWARFUnit &cu,
+ llvm::function_ref<bool(DWARFDIE die)> callback) = 0;
+ virtual void
+ GetObjCMethods(ConstString class_name,
+ llvm::function_ref<bool(DWARFDIE die)> callback) = 0;
+ virtual void
+ GetCompleteObjCClass(ConstString class_name, bool must_be_implementation,
+ llvm::function_ref<bool(DWARFDIE die)> callback) = 0;
+ virtual void GetTypes(ConstString name,
+ llvm::function_ref<bool(DWARFDIE die)> callback) = 0;
+ virtual void GetTypes(const DWARFDeclContext &context,
+ llvm::function_ref<bool(DWARFDIE die)> callback) = 0;
+
+ /// Finds all DIEs whose fully qualified name matches `context`. A base
+ /// implementation is provided, and it uses the entire CU to check the DIE
+ /// parent hierarchy. Specializations should override this if they are able
+ /// to provide a faster implementation.
+ virtual void
+ GetFullyQualifiedType(const DWARFDeclContext &context,
+ llvm::function_ref<bool(DWARFDIE die)> callback);
+ virtual void
+ GetNamespaces(ConstString name,
+ llvm::function_ref<bool(DWARFDIE die)> callback) = 0;
+ virtual void
+ GetFunctions(const Module::LookupInfo &lookup_info, SymbolFileDWARF &dwarf,
+ const CompilerDeclContext &parent_decl_ctx,
+ llvm::function_ref<bool(DWARFDIE die)> callback) = 0;
+ virtual void
+ GetFunctions(const RegularExpression &regex,
+ llvm::function_ref<bool(DWARFDIE die)> callback) = 0;
+
+ virtual void Dump(Stream &s) = 0;
+
+ StatsDuration::Duration GetIndexTime() { return m_index_time; }
+
+protected:
+ Module &m_module;
+ StatsDuration m_index_time;
+
+ /// Helper function implementing common logic for processing function dies. If
+ /// the function given by "die" matches search criteria given by
+ /// "parent_decl_ctx" and "name_type_mask", it calls the callback with the
+ /// given die.
+ bool ProcessFunctionDIE(const Module::LookupInfo &lookup_info, DWARFDIE die,
+ const CompilerDeclContext &parent_decl_ctx,
+ llvm::function_ref<bool(DWARFDIE die)> callback);
+
+ class DIERefCallbackImpl {
+ public:
+ DIERefCallbackImpl(const DWARFIndex &index,
+ llvm::function_ref<bool(DWARFDIE die)> callback,
+ llvm::StringRef name);
+ bool operator()(DIERef ref) const;
+ bool operator()(const llvm::AppleAcceleratorTable::Entry &entry) const;
+
+ private:
+ const DWARFIndex &m_index;
+ SymbolFileDWARF &m_dwarf;
+ const llvm::function_ref<bool(DWARFDIE die)> m_callback;
+ const llvm::StringRef m_name;
+ };
+ DIERefCallbackImpl
+ DIERefCallback(llvm::function_ref<bool(DWARFDIE die)> callback,
+ llvm::StringRef name = {}) const {
+ return DIERefCallbackImpl(*this, callback, name);
+ }
+
+ void ReportInvalidDIERef(DIERef ref, llvm::StringRef name) const;
+
+ /// Implementation of `GetFullyQualifiedType` to check a single entry,
+ /// shareable with derived classes.
+ bool
+ GetFullyQualifiedTypeImpl(const DWARFDeclContext &context, DWARFDIE die,
+ llvm::function_ref<bool(DWARFDIE die)> callback);
+};
+} // namespace dwarf
+} // namespace lldb_private::plugin
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFINDEX_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.cpp
new file mode 100644
index 000000000000..4f3a3f544653
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.cpp
@@ -0,0 +1,25 @@
+//===-- DWARFTypeUnit.cpp -------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFTypeUnit.h"
+
+#include "SymbolFileDWARF.h"
+#include "lldb/Utility/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::plugin::dwarf;
+
+void DWARFTypeUnit::Dump(Stream *s) const {
+ s->Format("{0:x16}: Type Unit: length = {1:x8}, version = {2:x4}, "
+ "abbr_offset = {3:x8}, addr_size = {4:x2} (next CU at "
+ "[{5:x16}])\n",
+ GetOffset(), (uint32_t)GetLength(), GetVersion(),
+ (uint32_t)GetAbbrevOffset(), GetAddressByteSize(),
+ GetNextUnitOffset());
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h
new file mode 100644
index 000000000000..8c1f932d8c7f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h
@@ -0,0 +1,45 @@
+//===-- DWARFTypeUnit.h -----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFTYPEUNIT_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFTYPEUNIT_H
+
+#include "DWARFUnit.h"
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+class DWARFAbbreviationDeclarationSet;
+} // namespace llvm
+
+namespace lldb_private::plugin {
+namespace dwarf {
+class DWARFTypeUnit : public DWARFUnit {
+public:
+ void BuildAddressRangeTable(DWARFDebugAranges *debug_aranges) override {}
+
+ void Dump(Stream *s) const override;
+
+ uint64_t GetTypeHash() { return m_header.getTypeHash(); }
+
+ dw_offset_t GetTypeOffset() { return GetOffset() + m_header.getTypeOffset(); }
+
+ static bool classof(const DWARFUnit *unit) { return unit->IsTypeUnit(); }
+
+private:
+ DWARFTypeUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid,
+ const llvm::DWARFUnitHeader &header,
+ const llvm::DWARFAbbreviationDeclarationSet &abbrevs,
+ DIERef::Section section, bool is_dwo)
+ : DWARFUnit(dwarf, uid, header, abbrevs, section, is_dwo) {}
+
+ friend class DWARFUnit;
+};
+} // namespace dwarf
+} // namespace lldb_private::plugin
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFTYPEUNIT_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
new file mode 100644
index 000000000000..66a762bf9b68
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
@@ -0,0 +1,1088 @@
+//===-- DWARFUnit.cpp -----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFUnit.h"
+
+#include "lldb/Core/Module.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/Timer.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
+#include "llvm/Object/Error.h"
+
+#include "DWARFCompileUnit.h"
+#include "DWARFDebugAranges.h"
+#include "DWARFDebugInfo.h"
+#include "DWARFTypeUnit.h"
+#include "LogChannelDWARF.h"
+#include "SymbolFileDWARFDwo.h"
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::dwarf;
+using namespace lldb_private::plugin::dwarf;
+
+extern int g_verbose;
+
+DWARFUnit::DWARFUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid,
+ const llvm::DWARFUnitHeader &header,
+ const llvm::DWARFAbbreviationDeclarationSet &abbrevs,
+ DIERef::Section section, bool is_dwo)
+ : UserID(uid), m_dwarf(dwarf), m_header(header), m_abbrevs(&abbrevs),
+ m_cancel_scopes(false), m_section(section), m_is_dwo(is_dwo),
+ m_has_parsed_non_skeleton_unit(false), m_dwo_id(header.getDWOId()) {}
+
+DWARFUnit::~DWARFUnit() = default;
+
+// Parses first DIE of a compile unit, excluding DWO.
+void DWARFUnit::ExtractUnitDIENoDwoIfNeeded() {
+ {
+ llvm::sys::ScopedReader lock(m_first_die_mutex);
+ if (m_first_die)
+ return; // Already parsed
+ }
+ llvm::sys::ScopedWriter lock(m_first_die_mutex);
+ if (m_first_die)
+ return; // Already parsed
+
+ ElapsedTime elapsed(m_dwarf.GetDebugInfoParseTimeRef());
+
+ // Set the offset to that of the first DIE and calculate the start of the
+ // next compilation unit header.
+ lldb::offset_t offset = GetFirstDIEOffset();
+
+ // We are in our compile unit, parse starting at the offset we were told to
+ // parse
+ const DWARFDataExtractor &data = GetData();
+ if (offset < GetNextUnitOffset() &&
+ m_first_die.Extract(data, *this, &offset)) {
+ AddUnitDIE(m_first_die);
+ return;
+ }
+}
+
+// Parses first DIE of a compile unit including DWO.
+void DWARFUnit::ExtractUnitDIEIfNeeded() {
+ ExtractUnitDIENoDwoIfNeeded();
+
+ if (m_has_parsed_non_skeleton_unit)
+ return;
+
+ m_has_parsed_non_skeleton_unit = true;
+ m_dwo_error.Clear();
+
+ if (!m_dwo_id)
+ return; // No DWO file.
+
+ std::shared_ptr<SymbolFileDWARFDwo> dwo_symbol_file =
+ m_dwarf.GetDwoSymbolFileForCompileUnit(*this, m_first_die);
+ if (!dwo_symbol_file)
+ return;
+
+ DWARFUnit *dwo_cu = dwo_symbol_file->GetDWOCompileUnitForHash(*m_dwo_id);
+
+ if (!dwo_cu) {
+ SetDwoError(Status::createWithFormat(
+ "unable to load .dwo file from \"{0}\" due to ID ({1:x16}) mismatch "
+ "for skeleton DIE at {2:x8}",
+ dwo_symbol_file->GetObjectFile()->GetFileSpec().GetPath().c_str(),
+ *m_dwo_id, m_first_die.GetOffset()));
+ return; // Can't fetch the compile unit from the dwo file.
+ }
+ // If the skeleton compile unit gets its unit DIE parsed first, then this
+ // will fill in the DWO file's back pointer to this skeleton compile unit.
+ // If the DWO files get parsed on their own first the skeleton back link
+ // can be done manually in DWARFUnit::GetSkeletonCompileUnit() which will
+ // do a reverse lookup and cache the result.
+ dwo_cu->SetSkeletonUnit(this);
+
+ DWARFBaseDIE dwo_cu_die = dwo_cu->GetUnitDIEOnly();
+ if (!dwo_cu_die.IsValid()) {
+ // Can't fetch the compile unit DIE from the dwo file.
+ SetDwoError(Status::createWithFormat(
+ "unable to extract compile unit DIE from .dwo file for skeleton "
+ "DIE at {0:x16}",
+ m_first_die.GetOffset()));
+ return;
+ }
+
+ // Here for DWO CU we want to use the address base set in the skeleton unit
+ // (DW_AT_addr_base) if it is available and use the DW_AT_GNU_addr_base
+ // otherwise. We do that because pre-DWARF v5 could use the DW_AT_GNU_*
+ // attributes which were applicable to the DWO units. The corresponding
+ // DW_AT_* attributes standardized in DWARF v5 are also applicable to the
+ // main unit in contrast.
+ if (m_addr_base)
+ dwo_cu->SetAddrBase(*m_addr_base);
+ else if (m_gnu_addr_base)
+ dwo_cu->SetAddrBase(*m_gnu_addr_base);
+
+ if (GetVersion() <= 4 && m_gnu_ranges_base)
+ dwo_cu->SetRangesBase(*m_gnu_ranges_base);
+ else if (dwo_symbol_file->GetDWARFContext()
+ .getOrLoadRngListsData()
+ .GetByteSize() > 0)
+ dwo_cu->SetRangesBase(llvm::DWARFListTableHeader::getHeaderSize(DWARF32));
+
+ if (GetVersion() >= 5 &&
+ dwo_symbol_file->GetDWARFContext().getOrLoadLocListsData().GetByteSize() >
+ 0)
+ dwo_cu->SetLoclistsBase(llvm::DWARFListTableHeader::getHeaderSize(DWARF32));
+
+ dwo_cu->SetBaseAddress(GetBaseAddress());
+
+ m_dwo = std::shared_ptr<DWARFUnit>(std::move(dwo_symbol_file), dwo_cu);
+}
+
+// Parses a compile unit and indexes its DIEs if it hasn't already been done.
+// It will leave this compile unit extracted forever.
+void DWARFUnit::ExtractDIEsIfNeeded() {
+ m_cancel_scopes = true;
+
+ {
+ llvm::sys::ScopedReader lock(m_die_array_mutex);
+ if (!m_die_array.empty())
+ return; // Already parsed
+ }
+ llvm::sys::ScopedWriter lock(m_die_array_mutex);
+ if (!m_die_array.empty())
+ return; // Already parsed
+
+ ExtractDIEsRWLocked();
+}
+
+// Parses a compile unit and indexes its DIEs if it hasn't already been done.
+// It will clear this compile unit after returned instance gets out of scope,
+// no other ScopedExtractDIEs instance is running for this compile unit
+// and no ExtractDIEsIfNeeded() has been executed during this ScopedExtractDIEs
+// lifetime.
+DWARFUnit::ScopedExtractDIEs DWARFUnit::ExtractDIEsScoped() {
+ ScopedExtractDIEs scoped(*this);
+
+ {
+ llvm::sys::ScopedReader lock(m_die_array_mutex);
+ if (!m_die_array.empty())
+ return scoped; // Already parsed
+ }
+ llvm::sys::ScopedWriter lock(m_die_array_mutex);
+ if (!m_die_array.empty())
+ return scoped; // Already parsed
+
+ // Otherwise m_die_array would be already populated.
+ lldbassert(!m_cancel_scopes);
+
+ ExtractDIEsRWLocked();
+ scoped.m_clear_dies = true;
+ return scoped;
+}
+
+DWARFUnit::ScopedExtractDIEs::ScopedExtractDIEs(DWARFUnit &cu) : m_cu(&cu) {
+ m_cu->m_die_array_scoped_mutex.lock_shared();
+}
+
+DWARFUnit::ScopedExtractDIEs::~ScopedExtractDIEs() {
+ if (!m_cu)
+ return;
+ m_cu->m_die_array_scoped_mutex.unlock_shared();
+ if (!m_clear_dies || m_cu->m_cancel_scopes)
+ return;
+ // Be sure no other ScopedExtractDIEs is running anymore.
+ llvm::sys::ScopedWriter lock_scoped(m_cu->m_die_array_scoped_mutex);
+ llvm::sys::ScopedWriter lock(m_cu->m_die_array_mutex);
+ if (m_cu->m_cancel_scopes)
+ return;
+ m_cu->ClearDIEsRWLocked();
+}
+
+DWARFUnit::ScopedExtractDIEs::ScopedExtractDIEs(ScopedExtractDIEs &&rhs)
+ : m_cu(rhs.m_cu), m_clear_dies(rhs.m_clear_dies) {
+ rhs.m_cu = nullptr;
+}
+
+DWARFUnit::ScopedExtractDIEs &
+DWARFUnit::ScopedExtractDIEs::operator=(DWARFUnit::ScopedExtractDIEs &&rhs) {
+ m_cu = rhs.m_cu;
+ rhs.m_cu = nullptr;
+ m_clear_dies = rhs.m_clear_dies;
+ return *this;
+}
+
+// Parses a compile unit and indexes its DIEs, m_die_array_mutex must be
+// held R/W and m_die_array must be empty.
+void DWARFUnit::ExtractDIEsRWLocked() {
+ llvm::sys::ScopedWriter first_die_lock(m_first_die_mutex);
+
+ ElapsedTime elapsed(m_dwarf.GetDebugInfoParseTimeRef());
+ LLDB_SCOPED_TIMERF(
+ "%s",
+ llvm::formatv("{0:x16}: DWARFUnit::ExtractDIEsIfNeeded()", GetOffset())
+ .str()
+ .c_str());
+
+ // Set the offset to that of the first DIE and calculate the start of the
+ // next compilation unit header.
+ lldb::offset_t offset = GetFirstDIEOffset();
+ lldb::offset_t next_cu_offset = GetNextUnitOffset();
+
+ DWARFDebugInfoEntry die;
+
+ uint32_t depth = 0;
+ // We are in our compile unit, parse starting at the offset we were told to
+ // parse
+ const DWARFDataExtractor &data = GetData();
+ std::vector<uint32_t> die_index_stack;
+ die_index_stack.reserve(32);
+ die_index_stack.push_back(0);
+ bool prev_die_had_children = false;
+ while (offset < next_cu_offset && die.Extract(data, *this, &offset)) {
+ const bool null_die = die.IsNULL();
+ if (depth == 0) {
+ assert(m_die_array.empty() && "Compile unit DIE already added");
+
+ // The average bytes per DIE entry has been seen to be around 14-20 so
+ // lets pre-reserve half of that since we are now stripping the NULL
+ // tags.
+
+ // Only reserve the memory if we are adding children of the main
+ // compile unit DIE. The compile unit DIE is always the first entry, so
+ // if our size is 1, then we are adding the first compile unit child
+ // DIE and should reserve the memory.
+ m_die_array.reserve(GetDebugInfoSize() / 24);
+ m_die_array.push_back(die);
+
+ if (!m_first_die)
+ AddUnitDIE(m_die_array.front());
+
+ // With -fsplit-dwarf-inlining, clang will emit non-empty skeleton compile
+ // units. We are not able to access these DIE *and* the dwo file
+ // simultaneously. We also don't need to do that as the dwo file will
+ // contain a superset of information. So, we don't even attempt to parse
+ // any remaining DIEs.
+ if (m_dwo) {
+ m_die_array.front().SetHasChildren(false);
+ break;
+ }
+
+ } else {
+ if (null_die) {
+ if (prev_die_had_children) {
+ // This will only happen if a DIE says is has children but all it
+ // contains is a NULL tag. Since we are removing the NULL DIEs from
+ // the list (saves up to 25% in C++ code), we need a way to let the
+ // DIE know that it actually doesn't have children.
+ if (!m_die_array.empty())
+ m_die_array.back().SetHasChildren(false);
+ }
+ } else {
+ die.SetParentIndex(m_die_array.size() - die_index_stack[depth - 1]);
+
+ if (die_index_stack.back())
+ m_die_array[die_index_stack.back()].SetSiblingIndex(
+ m_die_array.size() - die_index_stack.back());
+
+ // Only push the DIE if it isn't a NULL DIE
+ m_die_array.push_back(die);
+ }
+ }
+
+ if (null_die) {
+ // NULL DIE.
+ if (!die_index_stack.empty())
+ die_index_stack.pop_back();
+
+ if (depth > 0)
+ --depth;
+ prev_die_had_children = false;
+ } else {
+ die_index_stack.back() = m_die_array.size() - 1;
+ // Normal DIE
+ const bool die_has_children = die.HasChildren();
+ if (die_has_children) {
+ die_index_stack.push_back(0);
+ ++depth;
+ }
+ prev_die_had_children = die_has_children;
+ }
+
+ if (depth == 0)
+ break; // We are done with this compile unit!
+ }
+
+ if (!m_die_array.empty()) {
+ // The last die cannot have children (if it did, it wouldn't be the last
+ // one). This only makes a difference for malformed dwarf that does not have
+ // a terminating null die.
+ m_die_array.back().SetHasChildren(false);
+
+ if (m_first_die) {
+ // Only needed for the assertion.
+ m_first_die.SetHasChildren(m_die_array.front().HasChildren());
+ lldbassert(m_first_die == m_die_array.front());
+ }
+ m_first_die = m_die_array.front();
+ }
+
+ m_die_array.shrink_to_fit();
+
+ if (m_dwo)
+ m_dwo->ExtractDIEsIfNeeded();
+}
+
+// This is used when a split dwarf is enabled.
+// A skeleton compilation unit may contain the DW_AT_str_offsets_base attribute
+// that points to the first string offset of the CU contribution to the
+// .debug_str_offsets. At the same time, the corresponding split debug unit also
+// may use DW_FORM_strx* forms pointing to its own .debug_str_offsets.dwo and
+// for that case, we should find the offset (skip the section header).
+void DWARFUnit::SetDwoStrOffsetsBase() {
+ lldb::offset_t baseOffset = 0;
+
+ if (const llvm::DWARFUnitIndex::Entry *entry = m_header.getIndexEntry()) {
+ if (const auto *contribution =
+ entry->getContribution(llvm::DW_SECT_STR_OFFSETS))
+ baseOffset = contribution->getOffset();
+ else
+ return;
+ }
+
+ if (GetVersion() >= 5) {
+ const DWARFDataExtractor &strOffsets =
+ GetSymbolFileDWARF().GetDWARFContext().getOrLoadStrOffsetsData();
+ uint64_t length = strOffsets.GetU32(&baseOffset);
+ if (length == 0xffffffff)
+ length = strOffsets.GetU64(&baseOffset);
+
+ // Check version.
+ if (strOffsets.GetU16(&baseOffset) < 5)
+ return;
+
+ // Skip padding.
+ baseOffset += 2;
+ }
+
+ SetStrOffsetsBase(baseOffset);
+}
+
+std::optional<uint64_t> DWARFUnit::GetDWOId() {
+ ExtractUnitDIENoDwoIfNeeded();
+ return m_dwo_id;
+}
+
+// m_die_array_mutex must be already held as read/write.
+void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) {
+ DWARFAttributes attributes = cu_die.GetAttributes(this);
+
+ // Extract DW_AT_addr_base first, as other attributes may need it.
+ for (size_t i = 0; i < attributes.Size(); ++i) {
+ if (attributes.AttributeAtIndex(i) != DW_AT_addr_base)
+ continue;
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(i, form_value)) {
+ SetAddrBase(form_value.Unsigned());
+ break;
+ }
+ }
+
+ for (size_t i = 0; i < attributes.Size(); ++i) {
+ dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (!attributes.ExtractFormValueAtIndex(i, form_value))
+ continue;
+ switch (attr) {
+ default:
+ break;
+ case DW_AT_loclists_base:
+ SetLoclistsBase(form_value.Unsigned());
+ break;
+ case DW_AT_rnglists_base:
+ SetRangesBase(form_value.Unsigned());
+ break;
+ case DW_AT_str_offsets_base:
+ SetStrOffsetsBase(form_value.Unsigned());
+ break;
+ case DW_AT_low_pc:
+ SetBaseAddress(form_value.Address());
+ break;
+ case DW_AT_entry_pc:
+ // If the value was already set by DW_AT_low_pc, don't update it.
+ if (m_base_addr == LLDB_INVALID_ADDRESS)
+ SetBaseAddress(form_value.Address());
+ break;
+ case DW_AT_stmt_list:
+ m_line_table_offset = form_value.Unsigned();
+ break;
+ case DW_AT_GNU_addr_base:
+ m_gnu_addr_base = form_value.Unsigned();
+ break;
+ case DW_AT_GNU_ranges_base:
+ m_gnu_ranges_base = form_value.Unsigned();
+ break;
+ case DW_AT_GNU_dwo_id:
+ m_dwo_id = form_value.Unsigned();
+ break;
+ }
+ }
+
+ if (m_is_dwo) {
+ m_has_parsed_non_skeleton_unit = true;
+ SetDwoStrOffsetsBase();
+ return;
+ }
+}
+
+size_t DWARFUnit::GetDebugInfoSize() const {
+ return GetLengthByteSize() + GetLength() - GetHeaderByteSize();
+}
+
+const llvm::DWARFAbbreviationDeclarationSet *
+DWARFUnit::GetAbbreviations() const {
+ return m_abbrevs;
+}
+
+dw_offset_t DWARFUnit::GetAbbrevOffset() const {
+ return m_abbrevs ? m_abbrevs->getOffset() : DW_INVALID_OFFSET;
+}
+
+dw_offset_t DWARFUnit::GetLineTableOffset() {
+ ExtractUnitDIENoDwoIfNeeded();
+ return m_line_table_offset;
+}
+
+void DWARFUnit::SetAddrBase(dw_addr_t addr_base) { m_addr_base = addr_base; }
+
+// Parse the rangelist table header, including the optional array of offsets
+// following it (DWARF v5 and later).
+template <typename ListTableType>
+static llvm::Expected<ListTableType>
+ParseListTableHeader(const llvm::DWARFDataExtractor &data, uint64_t offset,
+ DwarfFormat format) {
+ // We are expected to be called with Offset 0 or pointing just past the table
+ // header. Correct Offset in the latter case so that it points to the start
+ // of the header.
+ if (offset == 0) {
+ // This means DW_AT_rnglists_base is missing and therefore DW_FORM_rnglistx
+ // cannot be handled. Returning a default-constructed ListTableType allows
+ // DW_FORM_sec_offset to be supported.
+ return ListTableType();
+ }
+
+ uint64_t HeaderSize = llvm::DWARFListTableHeader::getHeaderSize(format);
+ if (offset < HeaderSize)
+ return llvm::createStringError(std::errc::invalid_argument,
+ "did not detect a valid"
+ " list table with base = 0x%" PRIx64 "\n",
+ offset);
+ offset -= HeaderSize;
+ ListTableType Table;
+ if (llvm::Error E = Table.extractHeaderAndOffsets(data, &offset))
+ return std::move(E);
+ return Table;
+}
+
+void DWARFUnit::SetLoclistsBase(dw_addr_t loclists_base) {
+ uint64_t offset = 0;
+ if (const llvm::DWARFUnitIndex::Entry *entry = m_header.getIndexEntry()) {
+ const auto *contribution = entry->getContribution(llvm::DW_SECT_LOCLISTS);
+ if (!contribution) {
+ GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(
+ "Failed to find location list contribution for CU with DWO Id "
+ "{0:x16}",
+ *GetDWOId());
+ return;
+ }
+ offset += contribution->getOffset();
+ }
+ m_loclists_base = loclists_base;
+
+ uint64_t header_size = llvm::DWARFListTableHeader::getHeaderSize(DWARF32);
+ if (loclists_base < header_size)
+ return;
+
+ m_loclist_table_header.emplace(".debug_loclists", "locations");
+ offset += loclists_base - header_size;
+ if (llvm::Error E = m_loclist_table_header->extract(
+ m_dwarf.GetDWARFContext().getOrLoadLocListsData().GetAsLLVMDWARF(),
+ &offset)) {
+ GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(
+ "Failed to extract location list table at offset {0:x16} (location "
+ "list base: {1:x16}): {2}",
+ offset, loclists_base, toString(std::move(E)).c_str());
+ }
+}
+
+std::unique_ptr<llvm::DWARFLocationTable>
+DWARFUnit::GetLocationTable(const DataExtractor &data) const {
+ llvm::DWARFDataExtractor llvm_data(
+ data.GetData(), data.GetByteOrder() == lldb::eByteOrderLittle,
+ data.GetAddressByteSize());
+
+ if (m_is_dwo || GetVersion() >= 5)
+ return std::make_unique<llvm::DWARFDebugLoclists>(llvm_data, GetVersion());
+ return std::make_unique<llvm::DWARFDebugLoc>(llvm_data);
+}
+
+DWARFDataExtractor DWARFUnit::GetLocationData() const {
+ DWARFContext &Ctx = GetSymbolFileDWARF().GetDWARFContext();
+ const DWARFDataExtractor &data =
+ GetVersion() >= 5 ? Ctx.getOrLoadLocListsData() : Ctx.getOrLoadLocData();
+ if (const llvm::DWARFUnitIndex::Entry *entry = m_header.getIndexEntry()) {
+ if (const auto *contribution = entry->getContribution(
+ GetVersion() >= 5 ? llvm::DW_SECT_LOCLISTS : llvm::DW_SECT_EXT_LOC))
+ return DWARFDataExtractor(data, contribution->getOffset(),
+ contribution->getLength32());
+ return DWARFDataExtractor();
+ }
+ return data;
+}
+
+DWARFDataExtractor DWARFUnit::GetRnglistData() const {
+ DWARFContext &Ctx = GetSymbolFileDWARF().GetDWARFContext();
+ const DWARFDataExtractor &data = Ctx.getOrLoadRngListsData();
+ if (const llvm::DWARFUnitIndex::Entry *entry = m_header.getIndexEntry()) {
+ if (const auto *contribution =
+ entry->getContribution(llvm::DW_SECT_RNGLISTS))
+ return DWARFDataExtractor(data, contribution->getOffset(),
+ contribution->getLength32());
+ GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(
+ "Failed to find range list contribution for CU with signature {0:x16}",
+ entry->getSignature());
+
+ return DWARFDataExtractor();
+ }
+ return data;
+}
+
+void DWARFUnit::SetRangesBase(dw_addr_t ranges_base) {
+ lldbassert(!m_rnglist_table_done);
+
+ m_ranges_base = ranges_base;
+}
+
+const std::optional<llvm::DWARFDebugRnglistTable> &
+DWARFUnit::GetRnglistTable() {
+ if (GetVersion() >= 5 && !m_rnglist_table_done) {
+ m_rnglist_table_done = true;
+ if (auto table_or_error =
+ ParseListTableHeader<llvm::DWARFDebugRnglistTable>(
+ GetRnglistData().GetAsLLVMDWARF(), m_ranges_base, DWARF32))
+ m_rnglist_table = std::move(table_or_error.get());
+ else
+ GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(
+ "Failed to extract range list table at offset {0:x16}: {1}",
+ m_ranges_base, toString(table_or_error.takeError()).c_str());
+ }
+ return m_rnglist_table;
+}
+
+// This function is called only for DW_FORM_rnglistx.
+llvm::Expected<uint64_t> DWARFUnit::GetRnglistOffset(uint32_t Index) {
+ if (!GetRnglistTable())
+ return llvm::createStringError(std::errc::invalid_argument,
+ "missing or invalid range list table");
+ if (!m_ranges_base)
+ return llvm::createStringError(
+ std::errc::invalid_argument,
+ llvm::formatv("DW_FORM_rnglistx cannot be used without "
+ "DW_AT_rnglists_base for CU at {0:x16}",
+ GetOffset())
+ .str()
+ .c_str());
+ if (std::optional<uint64_t> off = GetRnglistTable()->getOffsetEntry(
+ GetRnglistData().GetAsLLVM(), Index))
+ return *off + m_ranges_base;
+ return llvm::createStringError(
+ std::errc::invalid_argument,
+ "invalid range list table index %u; OffsetEntryCount is %u, "
+ "DW_AT_rnglists_base is %" PRIu64,
+ Index, GetRnglistTable()->getOffsetEntryCount(), m_ranges_base);
+}
+
+void DWARFUnit::SetStrOffsetsBase(dw_offset_t str_offsets_base) {
+ m_str_offsets_base = str_offsets_base;
+}
+
+dw_addr_t DWARFUnit::ReadAddressFromDebugAddrSection(uint32_t index) const {
+ uint32_t index_size = GetAddressByteSize();
+ dw_offset_t addr_base = GetAddrBase();
+ dw_addr_t offset = addr_base + static_cast<dw_addr_t>(index) * index_size;
+ const DWARFDataExtractor &data =
+ m_dwarf.GetDWARFContext().getOrLoadAddrData();
+ if (data.ValidOffsetForDataOfSize(offset, index_size))
+ return data.GetMaxU64_unchecked(&offset, index_size);
+ return LLDB_INVALID_ADDRESS;
+}
+
+// It may be called only with m_die_array_mutex held R/W.
+void DWARFUnit::ClearDIEsRWLocked() {
+ m_die_array.clear();
+ m_die_array.shrink_to_fit();
+
+ if (m_dwo && !m_dwo->m_cancel_scopes)
+ m_dwo->ClearDIEsRWLocked();
+}
+
+lldb::ByteOrder DWARFUnit::GetByteOrder() const {
+ return m_dwarf.GetObjectFile()->GetByteOrder();
+}
+
+void DWARFUnit::SetBaseAddress(dw_addr_t base_addr) { m_base_addr = base_addr; }
+
+// Compare function DWARFDebugAranges::Range structures
+static bool CompareDIEOffset(const DWARFDebugInfoEntry &die,
+ const dw_offset_t die_offset) {
+ return die.GetOffset() < die_offset;
+}
+
+// GetDIE()
+//
+// Get the DIE (Debug Information Entry) with the specified offset by first
+// checking if the DIE is contained within this compile unit and grabbing the
+// DIE from this compile unit. Otherwise we grab the DIE from the DWARF file.
+DWARFDIE
+DWARFUnit::GetDIE(dw_offset_t die_offset) {
+ if (die_offset == DW_INVALID_OFFSET)
+ return DWARFDIE(); // Not found
+
+ if (!ContainsDIEOffset(die_offset)) {
+ GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(
+ "GetDIE for DIE {0:x16} is outside of its CU {0:x16}", die_offset,
+ GetOffset());
+ return DWARFDIE(); // Not found
+ }
+
+ ExtractDIEsIfNeeded();
+ DWARFDebugInfoEntry::const_iterator end = m_die_array.cend();
+ DWARFDebugInfoEntry::const_iterator pos =
+ lower_bound(m_die_array.cbegin(), end, die_offset, CompareDIEOffset);
+
+ if (pos != end && die_offset == (*pos).GetOffset())
+ return DWARFDIE(this, &(*pos));
+ return DWARFDIE(); // Not found
+}
+
+llvm::StringRef DWARFUnit::PeekDIEName(dw_offset_t die_offset) {
+ DWARFDebugInfoEntry die;
+ if (!die.Extract(GetData(), *this, &die_offset))
+ return llvm::StringRef();
+
+ // Does die contain a DW_AT_Name?
+ if (const char *name =
+ die.GetAttributeValueAsString(this, DW_AT_name, nullptr))
+ return name;
+
+ // Does its DW_AT_specification or DW_AT_abstract_origin contain an AT_Name?
+ for (auto attr : {DW_AT_specification, DW_AT_abstract_origin}) {
+ DWARFFormValue form_value;
+ if (!die.GetAttributeValue(this, attr, form_value))
+ continue;
+ auto [unit, offset] = form_value.ReferencedUnitAndOffset();
+ if (unit)
+ if (auto name = unit->PeekDIEName(offset); !name.empty())
+ return name;
+ }
+
+ return llvm::StringRef();
+}
+
+DWARFUnit &DWARFUnit::GetNonSkeletonUnit() {
+ ExtractUnitDIEIfNeeded();
+ if (m_dwo)
+ return *m_dwo;
+ return *this;
+}
+
+uint8_t DWARFUnit::GetAddressByteSize(const DWARFUnit *cu) {
+ if (cu)
+ return cu->GetAddressByteSize();
+ return DWARFUnit::GetDefaultAddressSize();
+}
+
+uint8_t DWARFUnit::GetDefaultAddressSize() { return 4; }
+
+DWARFCompileUnit *DWARFUnit::GetSkeletonUnit() {
+ if (m_skeleton_unit == nullptr && IsDWOUnit()) {
+ SymbolFileDWARFDwo *dwo =
+ llvm::dyn_cast_or_null<SymbolFileDWARFDwo>(&GetSymbolFileDWARF());
+ // Do a reverse lookup if the skeleton compile unit wasn't set.
+ if (dwo)
+ m_skeleton_unit = dwo->GetBaseSymbolFile().GetSkeletonUnit(this);
+ }
+ return llvm::dyn_cast_or_null<DWARFCompileUnit>(m_skeleton_unit);
+}
+
+void DWARFUnit::SetSkeletonUnit(DWARFUnit *skeleton_unit) {
+ // If someone is re-setting the skeleton compile unit backlink, make sure
+ // it is setting it to a valid value when it wasn't valid, or if the
+ // value in m_skeleton_unit was valid, it should be the same value.
+ assert(skeleton_unit);
+ assert(m_skeleton_unit == nullptr || m_skeleton_unit == skeleton_unit);
+ m_skeleton_unit = skeleton_unit;
+}
+
+bool DWARFUnit::Supports_DW_AT_APPLE_objc_complete_type() {
+ return GetProducer() != eProducerLLVMGCC;
+}
+
+bool DWARFUnit::DW_AT_decl_file_attributes_are_invalid() {
+ // llvm-gcc makes completely invalid decl file attributes and won't ever be
+ // fixed, so we need to know to ignore these.
+ return GetProducer() == eProducerLLVMGCC;
+}
+
+bool DWARFUnit::Supports_unnamed_objc_bitfields() {
+ if (GetProducer() == eProducerClang)
+ return GetProducerVersion() >= llvm::VersionTuple(425, 0, 13);
+ // Assume all other compilers didn't have incorrect ObjC bitfield info.
+ return true;
+}
+
+void DWARFUnit::ParseProducerInfo() {
+ m_producer = eProducerOther;
+ const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly();
+ if (!die)
+ return;
+
+ llvm::StringRef producer(
+ die->GetAttributeValueAsString(this, DW_AT_producer, nullptr));
+ if (producer.empty())
+ return;
+
+ static const RegularExpression g_swiftlang_version_regex(
+ llvm::StringRef(R"(swiftlang-([0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?))"));
+ static const RegularExpression g_clang_version_regex(
+ llvm::StringRef(R"(clang-([0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?))"));
+ static const RegularExpression g_llvm_gcc_regex(
+ llvm::StringRef(R"(4\.[012]\.[01] )"
+ R"(\(Based on Apple Inc\. build [0-9]+\) )"
+ R"(\(LLVM build [\.0-9]+\)$)"));
+
+ llvm::SmallVector<llvm::StringRef, 3> matches;
+ if (g_swiftlang_version_regex.Execute(producer, &matches)) {
+ m_producer_version.tryParse(matches[1]);
+ m_producer = eProducerSwift;
+ } else if (producer.contains("clang")) {
+ if (g_clang_version_regex.Execute(producer, &matches))
+ m_producer_version.tryParse(matches[1]);
+ m_producer = eProducerClang;
+ } else if (producer.contains("GNU")) {
+ m_producer = eProducerGCC;
+ } else if (g_llvm_gcc_regex.Execute(producer)) {
+ m_producer = eProducerLLVMGCC;
+ }
+}
+
+DWARFProducer DWARFUnit::GetProducer() {
+ if (m_producer == eProducerInvalid)
+ ParseProducerInfo();
+ return m_producer;
+}
+
+llvm::VersionTuple DWARFUnit::GetProducerVersion() {
+ if (m_producer_version.empty())
+ ParseProducerInfo();
+ return m_producer_version;
+}
+
+uint64_t DWARFUnit::GetDWARFLanguageType() {
+ if (m_language_type)
+ return *m_language_type;
+
+ const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly();
+ if (!die)
+ m_language_type = 0;
+ else
+ m_language_type = die->GetAttributeValueAsUnsigned(this, DW_AT_language, 0);
+ return *m_language_type;
+}
+
+bool DWARFUnit::GetIsOptimized() {
+ if (m_is_optimized == eLazyBoolCalculate) {
+ const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly();
+ if (die) {
+ m_is_optimized = eLazyBoolNo;
+ if (die->GetAttributeValueAsUnsigned(this, DW_AT_APPLE_optimized, 0) ==
+ 1) {
+ m_is_optimized = eLazyBoolYes;
+ }
+ }
+ }
+ return m_is_optimized == eLazyBoolYes;
+}
+
+FileSpec::Style DWARFUnit::GetPathStyle() {
+ if (!m_comp_dir)
+ ComputeCompDirAndGuessPathStyle();
+ return m_comp_dir->GetPathStyle();
+}
+
+const FileSpec &DWARFUnit::GetCompilationDirectory() {
+ if (!m_comp_dir)
+ ComputeCompDirAndGuessPathStyle();
+ return *m_comp_dir;
+}
+
+const FileSpec &DWARFUnit::GetAbsolutePath() {
+ if (!m_file_spec)
+ ComputeAbsolutePath();
+ return *m_file_spec;
+}
+
+FileSpec DWARFUnit::GetFile(size_t file_idx) {
+ return m_dwarf.GetFile(*this, file_idx);
+}
+
+// DWARF2/3 suggests the form hostname:pathname for compilation directory.
+// Remove the host part if present.
+static llvm::StringRef
+removeHostnameFromPathname(llvm::StringRef path_from_dwarf) {
+ if (!path_from_dwarf.contains(':'))
+ return path_from_dwarf;
+ llvm::StringRef host, path;
+ std::tie(host, path) = path_from_dwarf.split(':');
+
+ if (host.contains('/'))
+ return path_from_dwarf;
+
+ // check whether we have a windows path, and so the first character is a
+ // drive-letter not a hostname.
+ if (host.size() == 1 && llvm::isAlpha(host[0]) &&
+ (path.starts_with("\\") || path.starts_with("/")))
+ return path_from_dwarf;
+
+ return path;
+}
+
+void DWARFUnit::ComputeCompDirAndGuessPathStyle() {
+ m_comp_dir = FileSpec();
+ const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly();
+ if (!die)
+ return;
+
+ llvm::StringRef comp_dir = removeHostnameFromPathname(
+ die->GetAttributeValueAsString(this, DW_AT_comp_dir, nullptr));
+ if (!comp_dir.empty()) {
+ FileSpec::Style comp_dir_style =
+ FileSpec::GuessPathStyle(comp_dir).value_or(FileSpec::Style::native);
+ m_comp_dir = FileSpec(comp_dir, comp_dir_style);
+ } else {
+ // Try to detect the style based on the DW_AT_name attribute, but just store
+ // the detected style in the m_comp_dir field.
+ const char *name =
+ die->GetAttributeValueAsString(this, DW_AT_name, nullptr);
+ m_comp_dir = FileSpec(
+ "", FileSpec::GuessPathStyle(name).value_or(FileSpec::Style::native));
+ }
+}
+
+void DWARFUnit::ComputeAbsolutePath() {
+ m_file_spec = FileSpec();
+ const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly();
+ if (!die)
+ return;
+
+ m_file_spec =
+ FileSpec(die->GetAttributeValueAsString(this, DW_AT_name, nullptr),
+ GetPathStyle());
+
+ if (m_file_spec->IsRelative())
+ m_file_spec->MakeAbsolute(GetCompilationDirectory());
+}
+
+SymbolFileDWARFDwo *DWARFUnit::GetDwoSymbolFile(bool load_all_debug_info) {
+ if (load_all_debug_info)
+ ExtractUnitDIEIfNeeded();
+ if (m_dwo)
+ return &llvm::cast<SymbolFileDWARFDwo>(m_dwo->GetSymbolFileDWARF());
+ return nullptr;
+}
+
+const DWARFDebugAranges &DWARFUnit::GetFunctionAranges() {
+ if (m_func_aranges_up == nullptr) {
+ m_func_aranges_up = std::make_unique<DWARFDebugAranges>();
+ const DWARFDebugInfoEntry *die = DIEPtr();
+ if (die)
+ die->BuildFunctionAddressRangeTable(this, m_func_aranges_up.get());
+
+ if (m_dwo) {
+ const DWARFDebugInfoEntry *dwo_die = m_dwo->DIEPtr();
+ if (dwo_die)
+ dwo_die->BuildFunctionAddressRangeTable(m_dwo.get(),
+ m_func_aranges_up.get());
+ }
+
+ const bool minimize = false;
+ m_func_aranges_up->Sort(minimize);
+ }
+ return *m_func_aranges_up;
+}
+
+llvm::Expected<DWARFUnitSP>
+DWARFUnit::extract(SymbolFileDWARF &dwarf, user_id_t uid,
+ const DWARFDataExtractor &debug_info,
+ DIERef::Section section, lldb::offset_t *offset_ptr) {
+ assert(debug_info.ValidOffset(*offset_ptr));
+
+ DWARFContext &context = dwarf.GetDWARFContext();
+
+ // FIXME: Either properly map between DIERef::Section and
+ // llvm::DWARFSectionKind or switch to llvm's definition entirely.
+ llvm::DWARFSectionKind section_kind_llvm =
+ section == DIERef::Section::DebugInfo
+ ? llvm::DWARFSectionKind::DW_SECT_INFO
+ : llvm::DWARFSectionKind::DW_SECT_EXT_TYPES;
+
+ llvm::DWARFDataExtractor debug_info_llvm = debug_info.GetAsLLVMDWARF();
+ llvm::DWARFUnitHeader header;
+ if (llvm::Error extract_err = header.extract(
+ context.GetAsLLVM(), debug_info_llvm, offset_ptr, section_kind_llvm))
+ return std::move(extract_err);
+
+ if (context.isDwo()) {
+ const llvm::DWARFUnitIndex::Entry *entry = nullptr;
+ const llvm::DWARFUnitIndex &index = header.isTypeUnit()
+ ? context.GetAsLLVM().getTUIndex()
+ : context.GetAsLLVM().getCUIndex();
+ if (index) {
+ if (header.isTypeUnit())
+ entry = index.getFromHash(header.getTypeHash());
+ else if (auto dwo_id = header.getDWOId())
+ entry = index.getFromHash(*dwo_id);
+ }
+ if (!entry)
+ entry = index.getFromOffset(header.getOffset());
+ if (entry)
+ if (llvm::Error err = header.applyIndexEntry(entry))
+ return std::move(err);
+ }
+
+ const llvm::DWARFDebugAbbrev *abbr = dwarf.DebugAbbrev();
+ if (!abbr)
+ return llvm::make_error<llvm::object::GenericBinaryError>(
+ "No debug_abbrev data");
+
+ bool abbr_offset_OK =
+ dwarf.GetDWARFContext().getOrLoadAbbrevData().ValidOffset(
+ header.getAbbrOffset());
+ if (!abbr_offset_OK)
+ return llvm::make_error<llvm::object::GenericBinaryError>(
+ "Abbreviation offset for unit is not valid");
+
+ llvm::Expected<const llvm::DWARFAbbreviationDeclarationSet *> abbrevs_or_err =
+ abbr->getAbbreviationDeclarationSet(header.getAbbrOffset());
+ if (!abbrevs_or_err)
+ return abbrevs_or_err.takeError();
+
+ const llvm::DWARFAbbreviationDeclarationSet *abbrevs = *abbrevs_or_err;
+ if (!abbrevs)
+ return llvm::make_error<llvm::object::GenericBinaryError>(
+ "No abbrev exists at the specified offset.");
+
+ bool is_dwo = dwarf.GetDWARFContext().isDwo();
+ if (header.isTypeUnit())
+ return DWARFUnitSP(
+ new DWARFTypeUnit(dwarf, uid, header, *abbrevs, section, is_dwo));
+ return DWARFUnitSP(
+ new DWARFCompileUnit(dwarf, uid, header, *abbrevs, section, is_dwo));
+}
+
+const lldb_private::DWARFDataExtractor &DWARFUnit::GetData() const {
+ return m_section == DIERef::Section::DebugTypes
+ ? m_dwarf.GetDWARFContext().getOrLoadDebugTypesData()
+ : m_dwarf.GetDWARFContext().getOrLoadDebugInfoData();
+}
+
+uint32_t DWARFUnit::GetHeaderByteSize() const {
+ switch (m_header.getUnitType()) {
+ case llvm::dwarf::DW_UT_compile:
+ case llvm::dwarf::DW_UT_partial:
+ return GetVersion() < 5 ? 11 : 12;
+ case llvm::dwarf::DW_UT_skeleton:
+ case llvm::dwarf::DW_UT_split_compile:
+ return 20;
+ case llvm::dwarf::DW_UT_type:
+ case llvm::dwarf::DW_UT_split_type:
+ return GetVersion() < 5 ? 23 : 24;
+ }
+ llvm_unreachable("invalid UnitType.");
+}
+
+std::optional<uint64_t>
+DWARFUnit::GetStringOffsetSectionItem(uint32_t index) const {
+ offset_t offset = GetStrOffsetsBase() + index * 4;
+ return m_dwarf.GetDWARFContext().getOrLoadStrOffsetsData().GetU32(&offset);
+}
+
+llvm::Expected<DWARFRangeList>
+DWARFUnit::FindRnglistFromOffset(dw_offset_t offset) {
+ if (GetVersion() <= 4) {
+ const DWARFDebugRanges *debug_ranges = m_dwarf.GetDebugRanges();
+ if (!debug_ranges)
+ return llvm::make_error<llvm::object::GenericBinaryError>(
+ "No debug_ranges section");
+ return debug_ranges->FindRanges(this, offset);
+ }
+
+ if (!GetRnglistTable())
+ return llvm::createStringError(std::errc::invalid_argument,
+ "missing or invalid range list table");
+
+ llvm::DWARFDataExtractor data = GetRnglistData().GetAsLLVMDWARF();
+
+ // As DW_AT_rnglists_base may be missing we need to call setAddressSize.
+ data.setAddressSize(m_header.getAddressByteSize());
+ auto range_list_or_error = GetRnglistTable()->findList(data, offset);
+ if (!range_list_or_error)
+ return range_list_or_error.takeError();
+
+ llvm::Expected<llvm::DWARFAddressRangesVector> llvm_ranges =
+ range_list_or_error->getAbsoluteRanges(
+ llvm::object::SectionedAddress{GetBaseAddress()},
+ GetAddressByteSize(), [&](uint32_t index) {
+ uint32_t index_size = GetAddressByteSize();
+ dw_offset_t addr_base = GetAddrBase();
+ lldb::offset_t offset =
+ addr_base + static_cast<lldb::offset_t>(index) * index_size;
+ return llvm::object::SectionedAddress{
+ m_dwarf.GetDWARFContext().getOrLoadAddrData().GetMaxU64(
+ &offset, index_size)};
+ });
+ if (!llvm_ranges)
+ return llvm_ranges.takeError();
+
+ DWARFRangeList ranges;
+ for (const llvm::DWARFAddressRange &llvm_range : *llvm_ranges) {
+ ranges.Append(DWARFRangeList::Entry(llvm_range.LowPC,
+ llvm_range.HighPC - llvm_range.LowPC));
+ }
+ ranges.Sort();
+ return ranges;
+}
+
+llvm::Expected<DWARFRangeList> DWARFUnit::FindRnglistFromIndex(uint32_t index) {
+ llvm::Expected<uint64_t> maybe_offset = GetRnglistOffset(index);
+ if (!maybe_offset)
+ return maybe_offset.takeError();
+ return FindRnglistFromOffset(*maybe_offset);
+}
+
+bool DWARFUnit::HasAny(llvm::ArrayRef<dw_tag_t> tags) {
+ ExtractUnitDIEIfNeeded();
+ if (m_dwo)
+ return m_dwo->HasAny(tags);
+
+ for (const auto &die : m_die_array) {
+ for (const auto tag : tags) {
+ if (tag == die.Tag())
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h
new file mode 100644
index 000000000000..85c37971ced8
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h
@@ -0,0 +1,377 @@
+//===-- DWARFUnit.h ---------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFUNIT_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFUNIT_H
+
+#include "DWARFDIE.h"
+#include "DWARFDebugInfoEntry.h"
+#include "lldb/Utility/XcodeSDK.h"
+#include "lldb/lldb-enumerations.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h"
+#include "llvm/Support/RWMutex.h"
+#include <atomic>
+#include <optional>
+
+namespace lldb_private::plugin {
+namespace dwarf {
+class DWARFUnit;
+class DWARFCompileUnit;
+class NameToDIE;
+class SymbolFileDWARF;
+class SymbolFileDWARFDwo;
+
+typedef std::shared_ptr<DWARFUnit> DWARFUnitSP;
+
+enum DWARFProducer {
+ eProducerInvalid = 0,
+ eProducerClang,
+ eProducerGCC,
+ eProducerLLVMGCC,
+ eProducerSwift,
+ eProducerOther
+};
+
+class DWARFUnit : public UserID {
+ using die_iterator_range =
+ llvm::iterator_range<DWARFDebugInfoEntry::collection::iterator>;
+
+public:
+ static llvm::Expected<DWARFUnitSP>
+ extract(SymbolFileDWARF &dwarf2Data, lldb::user_id_t uid,
+ const DWARFDataExtractor &debug_info, DIERef::Section section,
+ lldb::offset_t *offset_ptr);
+ virtual ~DWARFUnit();
+
+ bool IsDWOUnit() { return m_is_dwo; }
+ /// Get the DWO ID from the DWARFUnitHeader for DWARF5, or from the unit DIE's
+ /// DW_AT_dwo_id or DW_AT_GNU_dwo_id for DWARF4 and earlier.
+ std::optional<uint64_t> GetDWOId();
+ /// Get the DWO ID from the DWARFUnitHeader only. DWARF5 skeleton units have
+ /// the DWO ID in the compile unit header and we sometimes only want to access
+ /// this cheap value without causing the more expensive attribute fetches that
+ /// GetDWOId() uses.
+ std::optional<uint64_t> GetHeaderDWOId() { return m_header.getDWOId(); }
+ void ExtractUnitDIEIfNeeded();
+ void ExtractUnitDIENoDwoIfNeeded();
+ void ExtractDIEsIfNeeded();
+
+ class ScopedExtractDIEs {
+ DWARFUnit *m_cu;
+
+ public:
+ bool m_clear_dies = false;
+ ScopedExtractDIEs(DWARFUnit &cu);
+ ~ScopedExtractDIEs();
+ ScopedExtractDIEs(const ScopedExtractDIEs &) = delete;
+ const ScopedExtractDIEs &operator=(const ScopedExtractDIEs &) = delete;
+ ScopedExtractDIEs(ScopedExtractDIEs &&rhs);
+ ScopedExtractDIEs &operator=(ScopedExtractDIEs &&rhs);
+ };
+ ScopedExtractDIEs ExtractDIEsScoped();
+
+ bool Verify(Stream *s) const;
+ virtual void Dump(Stream *s) const = 0;
+ /// Get the data that contains the DIE information for this unit.
+ ///
+ /// This will return the correct bytes that contain the data for
+ /// this DWARFUnit. It could be .debug_info or .debug_types
+ /// depending on where the data for this unit originates.
+ ///
+ /// \return
+ /// The correct data for the DIE information in this unit.
+ const DWARFDataExtractor &GetData() const;
+
+ /// Get the size in bytes of the unit header.
+ ///
+ /// \return
+ /// Byte size of the unit header
+ uint32_t GetHeaderByteSize() const;
+
+ // Offset of the initial length field.
+ dw_offset_t GetOffset() const { return m_header.getOffset(); }
+ /// Get the size in bytes of the length field in the header.
+ ///
+ /// In DWARF32 this is just 4 bytes
+ ///
+ /// \return
+ /// Byte size of the compile unit header length field
+ size_t GetLengthByteSize() const { return 4; }
+
+ bool ContainsDIEOffset(dw_offset_t die_offset) const {
+ return die_offset >= GetFirstDIEOffset() &&
+ die_offset < GetNextUnitOffset();
+ }
+ dw_offset_t GetFirstDIEOffset() const {
+ return GetOffset() + GetHeaderByteSize();
+ }
+ dw_offset_t GetNextUnitOffset() const { return m_header.getNextUnitOffset(); }
+ // Size of the CU data (without initial length and without header).
+ size_t GetDebugInfoSize() const;
+ // Size of the CU data incl. header but without initial length.
+ dw_offset_t GetLength() const { return m_header.getLength(); }
+ uint16_t GetVersion() const { return m_header.getVersion(); }
+ const llvm::DWARFAbbreviationDeclarationSet *GetAbbreviations() const;
+ dw_offset_t GetAbbrevOffset() const;
+ uint8_t GetAddressByteSize() const { return m_header.getAddressByteSize(); }
+ dw_addr_t GetAddrBase() const { return m_addr_base.value_or(0); }
+ dw_addr_t GetBaseAddress() const { return m_base_addr; }
+ dw_offset_t GetLineTableOffset();
+ dw_addr_t GetRangesBase() const { return m_ranges_base; }
+ dw_addr_t GetStrOffsetsBase() const { return m_str_offsets_base; }
+ void SetAddrBase(dw_addr_t addr_base);
+ void SetLoclistsBase(dw_addr_t loclists_base);
+ void SetRangesBase(dw_addr_t ranges_base);
+ void SetStrOffsetsBase(dw_offset_t str_offsets_base);
+ virtual void BuildAddressRangeTable(DWARFDebugAranges *debug_aranges) = 0;
+
+ dw_addr_t ReadAddressFromDebugAddrSection(uint32_t index) const;
+
+ lldb::ByteOrder GetByteOrder() const;
+
+ const DWARFDebugAranges &GetFunctionAranges();
+
+ void SetBaseAddress(dw_addr_t base_addr);
+
+ DWARFBaseDIE GetUnitDIEOnly() { return {this, GetUnitDIEPtrOnly()}; }
+
+ DWARFDIE DIE() { return DWARFDIE(this, DIEPtr()); }
+
+ DWARFDIE GetDIE(dw_offset_t die_offset);
+
+ /// Returns the AT_Name of the DIE at `die_offset`, if it exists, without
+ /// parsing the entire compile unit. An empty is string is returned upon
+ /// error or if the attribute is not present.
+ llvm::StringRef PeekDIEName(dw_offset_t die_offset);
+
+ DWARFUnit &GetNonSkeletonUnit();
+
+ static uint8_t GetAddressByteSize(const DWARFUnit *cu);
+
+ static uint8_t GetDefaultAddressSize();
+
+ lldb_private::CompileUnit *GetLLDBCompUnit() const { return m_lldb_cu; }
+
+ void SetLLDBCompUnit(lldb_private::CompileUnit *cu) { m_lldb_cu = cu; }
+
+ /// Get the skeleton compile unit for a DWO file.
+ ///
+ /// We need to keep track of the skeleton compile unit for a DWO file so
+ /// we can access it. Sometimes this value is cached when the skeleton
+ /// compile unit is first parsed, but if a .dwp file parses all of the
+ /// DWARFUnits in the file, the skeleton compile unit might not have been
+ /// parsed yet, to there might not be a backlink. This accessor handles
+ /// both cases correctly and avoids crashes.
+ DWARFCompileUnit *GetSkeletonUnit();
+
+ void SetSkeletonUnit(DWARFUnit *skeleton_unit);
+
+ bool Supports_DW_AT_APPLE_objc_complete_type();
+
+ bool DW_AT_decl_file_attributes_are_invalid();
+
+ bool Supports_unnamed_objc_bitfields();
+
+ SymbolFileDWARF &GetSymbolFileDWARF() const { return m_dwarf; }
+
+ DWARFProducer GetProducer();
+
+ llvm::VersionTuple GetProducerVersion();
+
+ uint64_t GetDWARFLanguageType();
+
+ bool GetIsOptimized();
+
+ const FileSpec &GetCompilationDirectory();
+ const FileSpec &GetAbsolutePath();
+ FileSpec GetFile(size_t file_idx);
+ FileSpec::Style GetPathStyle();
+
+ SymbolFileDWARFDwo *GetDwoSymbolFile(bool load_all_debug_info = true);
+
+ die_iterator_range dies() {
+ ExtractDIEsIfNeeded();
+ return die_iterator_range(m_die_array.begin(), m_die_array.end());
+ }
+
+ DIERef::Section GetDebugSection() const { return m_section; }
+
+ uint8_t GetUnitType() const { return m_header.getUnitType(); }
+ bool IsTypeUnit() const { return m_header.isTypeUnit(); }
+ /// Note that this check only works for DWARF5+.
+ bool IsSkeletonUnit() const {
+ return GetUnitType() == llvm::dwarf::DW_UT_skeleton;
+ }
+
+ std::optional<uint64_t> GetStringOffsetSectionItem(uint32_t index) const;
+
+ /// Return a list of address ranges resulting from a (possibly encoded)
+ /// range list starting at a given offset in the appropriate ranges section.
+ llvm::Expected<DWARFRangeList> FindRnglistFromOffset(dw_offset_t offset);
+
+ /// Return a list of address ranges retrieved from an encoded range
+ /// list whose offset is found via a table lookup given an index (DWARF v5
+ /// and later).
+ llvm::Expected<DWARFRangeList> FindRnglistFromIndex(uint32_t index);
+
+ /// Return a rangelist's offset based on an index. The index designates
+ /// an entry in the rangelist table's offset array and is supplied by
+ /// DW_FORM_rnglistx.
+ llvm::Expected<uint64_t> GetRnglistOffset(uint32_t Index);
+
+ std::optional<uint64_t> GetLoclistOffset(uint32_t Index) {
+ if (!m_loclist_table_header)
+ return std::nullopt;
+
+ std::optional<uint64_t> Offset = m_loclist_table_header->getOffsetEntry(
+ m_dwarf.GetDWARFContext().getOrLoadLocListsData().GetAsLLVM(), Index);
+ if (!Offset)
+ return std::nullopt;
+ return *Offset + m_loclists_base;
+ }
+
+ /// Return the location table for parsing the given location list data. The
+ /// format is chosen according to the unit type. Never returns null.
+ std::unique_ptr<llvm::DWARFLocationTable>
+ GetLocationTable(const DataExtractor &data) const;
+
+ DWARFDataExtractor GetLocationData() const;
+
+ /// Returns true if any DIEs in the unit match any DW_TAG values in \a tags.
+ ///
+ /// \param[in] tags
+ /// An array of dw_tag_t values to check all abbrevitions for.
+ ///
+ /// \returns
+ /// True if any DIEs match any tag in \a tags, false otherwise.
+ bool HasAny(llvm::ArrayRef<dw_tag_t> tags);
+
+ /// Get the fission .dwo file specific error for this compile unit.
+ ///
+ /// The skeleton compile unit only can have a DWO error. Any other type
+ /// of DWARFUnit will not have a valid DWO error.
+ ///
+ /// \returns
+ /// A valid DWO error if there is a problem with anything in the
+ /// locating or parsing inforamtion in the .dwo file
+ const Status &GetDwoError() const { return m_dwo_error; }
+
+ /// Set the fission .dwo file specific error for this compile unit.
+ ///
+ /// This helps tracks issues that arise when trying to locate or parse a
+ /// .dwo file. Things like a missing .dwo file, DWO ID mismatch, and other
+ /// .dwo errors can be stored in each compile unit so the issues can be
+ /// communicated to the user.
+ void SetDwoError(const Status &error) { m_dwo_error = error; }
+
+protected:
+ DWARFUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid,
+ const llvm::DWARFUnitHeader &header,
+ const llvm::DWARFAbbreviationDeclarationSet &abbrevs,
+ DIERef::Section section, bool is_dwo);
+
+ llvm::Error ExtractHeader(SymbolFileDWARF &dwarf,
+ const DWARFDataExtractor &data,
+ lldb::offset_t *offset_ptr);
+
+ // Get the DWARF unit DWARF debug information entry. Parse the single DIE
+ // if needed.
+ const DWARFDebugInfoEntry *GetUnitDIEPtrOnly() {
+ ExtractUnitDIENoDwoIfNeeded();
+ // m_first_die_mutex is not required as m_first_die is never cleared.
+ if (!m_first_die)
+ return nullptr;
+ return &m_first_die;
+ }
+
+ // Get all DWARF debug informration entries. Parse all DIEs if needed.
+ const DWARFDebugInfoEntry *DIEPtr() {
+ ExtractDIEsIfNeeded();
+ if (m_die_array.empty())
+ return nullptr;
+ return &m_die_array[0];
+ }
+
+ const std::optional<llvm::DWARFDebugRnglistTable> &GetRnglistTable();
+
+ DWARFDataExtractor GetRnglistData() const;
+
+ SymbolFileDWARF &m_dwarf;
+ std::shared_ptr<DWARFUnit> m_dwo;
+ llvm::DWARFUnitHeader m_header;
+ const llvm::DWARFAbbreviationDeclarationSet *m_abbrevs = nullptr;
+ lldb_private::CompileUnit *m_lldb_cu = nullptr;
+ // If this is a DWO file, we have a backlink to our skeleton compile unit.
+ DWARFUnit *m_skeleton_unit = nullptr;
+ // The compile unit debug information entry item
+ DWARFDebugInfoEntry::collection m_die_array;
+ mutable llvm::sys::RWMutex m_die_array_mutex;
+ // It is used for tracking of ScopedExtractDIEs instances.
+ mutable llvm::sys::RWMutex m_die_array_scoped_mutex;
+ // ScopedExtractDIEs instances should not call ClearDIEsRWLocked()
+ // as someone called ExtractDIEsIfNeeded().
+ std::atomic<bool> m_cancel_scopes;
+ // GetUnitDIEPtrOnly() needs to return pointer to the first DIE.
+ // But the first element of m_die_array after ExtractUnitDIEIfNeeded()
+ // would possibly move in memory after later ExtractDIEsIfNeeded().
+ DWARFDebugInfoEntry m_first_die;
+ llvm::sys::RWMutex m_first_die_mutex;
+ // A table similar to the .debug_aranges table, but this one points to the
+ // exact DW_TAG_subprogram DIEs
+ std::unique_ptr<DWARFDebugAranges> m_func_aranges_up;
+ dw_addr_t m_base_addr = 0;
+ DWARFProducer m_producer = eProducerInvalid;
+ llvm::VersionTuple m_producer_version;
+ std::optional<uint64_t> m_language_type;
+ LazyBool m_is_optimized = eLazyBoolCalculate;
+ std::optional<FileSpec> m_comp_dir;
+ std::optional<FileSpec> m_file_spec;
+ std::optional<dw_addr_t> m_addr_base; ///< Value of DW_AT_addr_base.
+ dw_addr_t m_loclists_base = 0; ///< Value of DW_AT_loclists_base.
+ dw_addr_t m_ranges_base = 0; ///< Value of DW_AT_rnglists_base.
+ std::optional<uint64_t> m_gnu_addr_base;
+ std::optional<uint64_t> m_gnu_ranges_base;
+
+ /// Value of DW_AT_stmt_list.
+ dw_offset_t m_line_table_offset = DW_INVALID_OFFSET;
+
+ dw_offset_t m_str_offsets_base = 0; // Value of DW_AT_str_offsets_base.
+
+ std::optional<llvm::DWARFDebugRnglistTable> m_rnglist_table;
+ bool m_rnglist_table_done = false;
+ std::optional<llvm::DWARFListTableHeader> m_loclist_table_header;
+
+ const DIERef::Section m_section;
+ bool m_is_dwo;
+ bool m_has_parsed_non_skeleton_unit;
+ /// Value of DW_AT_GNU_dwo_id (v4) or dwo_id from CU header (v5).
+ std::optional<uint64_t> m_dwo_id;
+ /// If we get an error when trying to load a .dwo file, save that error here.
+ /// Errors include .dwo/.dwp file not found, or the .dwp/.dwp file was found
+ /// but DWO ID doesn't match, etc.
+ Status m_dwo_error;
+
+private:
+ void ParseProducerInfo();
+ void ExtractDIEsRWLocked();
+ void ClearDIEsRWLocked();
+
+ void AddUnitDIE(const DWARFDebugInfoEntry &cu_die);
+ void SetDwoStrOffsetsBase();
+
+ void ComputeCompDirAndGuessPathStyle();
+ void ComputeAbsolutePath();
+
+ DWARFUnit(const DWARFUnit &) = delete;
+ const DWARFUnit &operator=(const DWARFUnit &) = delete;
+};
+} // namespace dwarf
+} // namespace lldb_private::plugin
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFUNIT_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp
new file mode 100644
index 000000000000..7e66b3dccf97
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp
@@ -0,0 +1,504 @@
+//===-- DebugNamesDWARFIndex.cpp ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h"
+#include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h"
+#include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h"
+#include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h"
+#include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/Stream.h"
+#include "llvm/ADT/Sequence.h"
+#include <optional>
+
+using namespace lldb_private;
+using namespace lldb;
+using namespace lldb_private::dwarf;
+using namespace lldb_private::plugin::dwarf;
+
+llvm::Expected<std::unique_ptr<DebugNamesDWARFIndex>>
+DebugNamesDWARFIndex::Create(Module &module, DWARFDataExtractor debug_names,
+ DWARFDataExtractor debug_str,
+ SymbolFileDWARF &dwarf) {
+ auto index_up = std::make_unique<DebugNames>(debug_names.GetAsLLVMDWARF(),
+ debug_str.GetAsLLVM());
+ if (llvm::Error E = index_up->extract())
+ return std::move(E);
+
+ return std::unique_ptr<DebugNamesDWARFIndex>(new DebugNamesDWARFIndex(
+ module, std::move(index_up), debug_names, debug_str, dwarf));
+}
+
+llvm::DenseSet<uint64_t>
+DebugNamesDWARFIndex::GetTypeUnitSignatures(const DebugNames &debug_names) {
+ llvm::DenseSet<uint64_t> result;
+ for (const DebugNames::NameIndex &ni : debug_names) {
+ const uint32_t num_tus = ni.getForeignTUCount();
+ for (uint32_t tu = 0; tu < num_tus; ++tu)
+ result.insert(ni.getForeignTUSignature(tu));
+ }
+ return result;
+}
+
+llvm::DenseSet<dw_offset_t>
+DebugNamesDWARFIndex::GetUnits(const DebugNames &debug_names) {
+ llvm::DenseSet<dw_offset_t> result;
+ for (const DebugNames::NameIndex &ni : debug_names) {
+ const uint32_t num_cus = ni.getCUCount();
+ for (uint32_t cu = 0; cu < num_cus; ++cu)
+ result.insert(ni.getCUOffset(cu));
+ const uint32_t num_tus = ni.getLocalTUCount();
+ for (uint32_t tu = 0; tu < num_tus; ++tu)
+ result.insert(ni.getLocalTUOffset(tu));
+ }
+ return result;
+}
+
+std::optional<DWARFTypeUnit *>
+DebugNamesDWARFIndex::GetForeignTypeUnit(const DebugNames::Entry &entry) const {
+ std::optional<uint64_t> type_sig = entry.getForeignTUTypeSignature();
+ if (!type_sig.has_value())
+ return std::nullopt;
+
+ // Ask the entry for the skeleton compile unit offset and fetch the .dwo
+ // file from it and get the type unit by signature from there. If we find
+ // the type unit in the .dwo file, we don't need to check that the
+ // DW_AT_dwo_name matches because each .dwo file can have its own type unit.
+ std::optional<uint64_t> cu_offset = entry.getRelatedCUOffset();
+ if (!cu_offset)
+ return nullptr; // Return NULL, this is a type unit, but couldn't find it.
+
+ DWARFUnit *cu =
+ m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, *cu_offset);
+ if (!cu)
+ return nullptr; // Return NULL, this is a type unit, but couldn't find it.
+
+ auto dwp_sp = m_debug_info.GetDwpSymbolFile();
+ if (!dwp_sp) {
+ // No .dwp file, we need to load the .dwo file.
+ DWARFUnit &dwo_cu = cu->GetNonSkeletonUnit();
+ // We don't need the check if the type unit matches the .dwo file if we have
+ // a .dwo file (not a .dwp), so we can just return the value here.
+ if (!dwo_cu.IsDWOUnit())
+ return nullptr; // We weren't able to load the .dwo file.
+ return dwo_cu.GetSymbolFileDWARF().DebugInfo().GetTypeUnitForHash(
+ *type_sig);
+ }
+ // We have a .dwp file, just get the type unit from there. We need to verify
+ // that the type unit that ended up in the final .dwp file is the right type
+ // unit. Type units have signatures which are the same across multiple .dwo
+ // files, but only one of those type units will end up in the .dwp file. The
+ // contents of type units for the same type can be different in different .dwo
+ // files, which means the DIE offsets might not be the same between two
+ // different type units. So we need to determine if this accelerator table
+ // matches the type unit that ended up in the .dwp file. If it doesn't match,
+ // then we need to ignore this accelerator table entry as the type unit that
+ // is in the .dwp file will have its own index. In order to determine if the
+ // type unit that ended up in a .dwp file matches this DebugNames::Entry, we
+ // need to find the skeleton compile unit for this entry.
+ DWARFTypeUnit *foreign_tu = dwp_sp->DebugInfo().GetTypeUnitForHash(*type_sig);
+ if (!foreign_tu)
+ return nullptr; // Return NULL, this is a type unit, but couldn't find it.
+
+ DWARFBaseDIE cu_die = cu->GetUnitDIEOnly();
+ DWARFBaseDIE tu_die = foreign_tu->GetUnitDIEOnly();
+ llvm::StringRef cu_dwo_name =
+ cu_die.GetAttributeValueAsString(DW_AT_dwo_name, nullptr);
+ llvm::StringRef tu_dwo_name =
+ tu_die.GetAttributeValueAsString(DW_AT_dwo_name, nullptr);
+ if (cu_dwo_name == tu_dwo_name)
+ return foreign_tu; // We found a match!
+ return nullptr; // Return NULL, this is a type unit, but couldn't find it.
+}
+
+DWARFUnit *
+DebugNamesDWARFIndex::GetNonSkeletonUnit(const DebugNames::Entry &entry) const {
+
+ if (std::optional<DWARFTypeUnit *> foreign_tu = GetForeignTypeUnit(entry))
+ return foreign_tu.value();
+
+ // Look for a DWARF unit offset (CU offset or local TU offset) as they are
+ // both offsets into the .debug_info section.
+ std::optional<uint64_t> unit_offset = entry.getCUOffset();
+ if (!unit_offset)
+ unit_offset = entry.getLocalTUOffset();
+ if (unit_offset) {
+ if (DWARFUnit *cu = m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo,
+ *unit_offset))
+ return &cu->GetNonSkeletonUnit();
+ }
+ return nullptr;
+}
+
+DWARFDIE DebugNamesDWARFIndex::GetDIE(const DebugNames::Entry &entry) const {
+ DWARFUnit *unit = GetNonSkeletonUnit(entry);
+ std::optional<uint64_t> die_offset = entry.getDIEUnitOffset();
+ if (!unit || !die_offset)
+ return DWARFDIE();
+ if (DWARFDIE die = unit->GetDIE(unit->GetOffset() + *die_offset))
+ return die;
+
+ m_module.ReportErrorIfModifyDetected(
+ "the DWARF debug information has been modified (bad offset {0:x} in "
+ "debug_names section)\n",
+ *die_offset);
+ return DWARFDIE();
+}
+
+bool DebugNamesDWARFIndex::ProcessEntry(
+ const DebugNames::Entry &entry,
+ llvm::function_ref<bool(DWARFDIE die)> callback) {
+ DWARFDIE die = GetDIE(entry);
+ if (!die)
+ return true;
+ // Clang used to erroneously emit index entries for declaration DIEs in case
+ // when the definition is in a type unit (llvm.org/pr77696).
+ if (die.IsStructUnionOrClass() &&
+ die.GetAttributeValueAsUnsigned(DW_AT_declaration, 0))
+ return true;
+ return callback(die);
+}
+
+void DebugNamesDWARFIndex::MaybeLogLookupError(llvm::Error error,
+ const DebugNames::NameIndex &ni,
+ llvm::StringRef name) {
+ // Ignore SentinelErrors, log everything else.
+ LLDB_LOG_ERROR(
+ GetLog(DWARFLog::Lookups),
+ handleErrors(std::move(error), [](const DebugNames::SentinelError &) {}),
+ "Failed to parse index entries for index at {1:x}, name {2}: {0}",
+ ni.getUnitOffset(), name);
+}
+
+void DebugNamesDWARFIndex::GetGlobalVariables(
+ ConstString basename, llvm::function_ref<bool(DWARFDIE die)> callback) {
+ for (const DebugNames::Entry &entry :
+ m_debug_names_up->equal_range(basename.GetStringRef())) {
+ if (entry.tag() != DW_TAG_variable)
+ continue;
+
+ if (!ProcessEntry(entry, callback))
+ return;
+ }
+
+ m_fallback.GetGlobalVariables(basename, callback);
+}
+
+void DebugNamesDWARFIndex::GetGlobalVariables(
+ const RegularExpression &regex,
+ llvm::function_ref<bool(DWARFDIE die)> callback) {
+ for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
+ for (DebugNames::NameTableEntry nte: ni) {
+ Mangled mangled_name(nte.getString());
+ if (!mangled_name.NameMatches(regex))
+ continue;
+
+ uint64_t entry_offset = nte.getEntryOffset();
+ llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
+ for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
+ if (entry_or->tag() != DW_TAG_variable)
+ continue;
+
+ if (!ProcessEntry(*entry_or, callback))
+ return;
+ }
+ MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
+ }
+ }
+
+ m_fallback.GetGlobalVariables(regex, callback);
+}
+
+void DebugNamesDWARFIndex::GetGlobalVariables(
+ DWARFUnit &cu, llvm::function_ref<bool(DWARFDIE die)> callback) {
+ uint64_t cu_offset = cu.GetOffset();
+ bool found_entry_for_cu = false;
+ for (const DebugNames::NameIndex &ni : *m_debug_names_up) {
+ // Check if this name index contains an entry for the given CU.
+ bool cu_matches = false;
+ for (uint32_t i = 0; i < ni.getCUCount(); ++i) {
+ if (ni.getCUOffset(i) == cu_offset) {
+ cu_matches = true;
+ break;
+ }
+ }
+ if (!cu_matches)
+ continue;
+
+ for (DebugNames::NameTableEntry nte : ni) {
+ uint64_t entry_offset = nte.getEntryOffset();
+ llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
+ for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
+ if (entry_or->tag() != DW_TAG_variable)
+ continue;
+ if (entry_or->getCUOffset() != cu_offset)
+ continue;
+
+ found_entry_for_cu = true;
+ if (!ProcessEntry(*entry_or, callback))
+ return;
+ }
+ MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
+ }
+ }
+ // If no name index for that particular CU was found, fallback to
+ // creating the manual index.
+ if (!found_entry_for_cu)
+ m_fallback.GetGlobalVariables(cu, callback);
+}
+
+void DebugNamesDWARFIndex::GetCompleteObjCClass(
+ ConstString class_name, bool must_be_implementation,
+ llvm::function_ref<bool(DWARFDIE die)> callback) {
+ // Keep a list of incomplete types as fallback for when we don't find the
+ // complete type.
+ std::vector<DWARFDIE> incomplete_types;
+
+ for (const DebugNames::Entry &entry :
+ m_debug_names_up->equal_range(class_name.GetStringRef())) {
+ if (entry.tag() != DW_TAG_structure_type &&
+ entry.tag() != DW_TAG_class_type)
+ continue;
+
+ DWARFDIE die = GetDIE(entry);
+ if (!die) {
+ // Report invalid
+ continue;
+ }
+ DWARFUnit *cu = die.GetCU();
+ if (!cu->Supports_DW_AT_APPLE_objc_complete_type()) {
+ incomplete_types.push_back(die);
+ continue;
+ }
+
+ if (die.GetAttributeValueAsUnsigned(DW_AT_APPLE_objc_complete_type, 0)) {
+ // If we find the complete version we're done.
+ callback(die);
+ return;
+ }
+ incomplete_types.push_back(die);
+ }
+
+ for (DWARFDIE die : incomplete_types)
+ if (!callback(die))
+ return;
+
+ m_fallback.GetCompleteObjCClass(class_name, must_be_implementation, callback);
+}
+
+namespace {
+using Entry = llvm::DWARFDebugNames::Entry;
+
+/// If `entry` and all of its parents have an `IDX_parent`, use that information
+/// to build and return a list of at most `max_parents` parent Entries.
+/// `entry` itself is not included in the list.
+/// If any parent does not have an `IDX_parent`, or the Entry data is corrupted,
+/// nullopt is returned.
+std::optional<llvm::SmallVector<Entry, 4>>
+getParentChain(Entry entry, uint32_t max_parents) {
+ llvm::SmallVector<Entry, 4> parent_entries;
+
+ do {
+ if (!entry.hasParentInformation())
+ return std::nullopt;
+
+ llvm::Expected<std::optional<Entry>> parent = entry.getParentDIEEntry();
+ if (!parent) {
+ // Bad data.
+ LLDB_LOG_ERROR(
+ GetLog(DWARFLog::Lookups), parent.takeError(),
+ "Failed to extract parent entry from a non-empty IDX_parent");
+ return std::nullopt;
+ }
+
+ // Last parent in the chain.
+ if (!parent->has_value())
+ break;
+
+ parent_entries.push_back(**parent);
+ entry = **parent;
+ } while (parent_entries.size() < max_parents);
+
+ return parent_entries;
+}
+} // namespace
+
+void DebugNamesDWARFIndex::GetFullyQualifiedType(
+ const DWARFDeclContext &context,
+ llvm::function_ref<bool(DWARFDIE die)> callback) {
+ if (context.GetSize() == 0)
+ return;
+
+ llvm::StringRef leaf_name = context[0].name;
+ llvm::SmallVector<llvm::StringRef> parent_names;
+ for (auto idx : llvm::seq<int>(1, context.GetSize()))
+ parent_names.emplace_back(context[idx].name);
+
+ // For each entry, grab its parent chain and check if we have a match.
+ for (const DebugNames::Entry &entry :
+ m_debug_names_up->equal_range(leaf_name)) {
+ if (!isType(entry.tag()))
+ continue;
+
+ // If we get a NULL foreign_tu back, the entry doesn't match the type unit
+ // in the .dwp file, or we were not able to load the .dwo file or the DWO ID
+ // didn't match.
+ std::optional<DWARFTypeUnit *> foreign_tu = GetForeignTypeUnit(entry);
+ if (foreign_tu && foreign_tu.value() == nullptr)
+ continue;
+
+ // Grab at most one extra parent, subsequent parents are not necessary to
+ // test equality.
+ std::optional<llvm::SmallVector<Entry, 4>> parent_chain =
+ getParentChain(entry, parent_names.size() + 1);
+
+ if (!parent_chain) {
+ // Fallback: use the base class implementation.
+ if (!ProcessEntry(entry, [&](DWARFDIE die) {
+ return GetFullyQualifiedTypeImpl(context, die, callback);
+ }))
+ return;
+ continue;
+ }
+
+ if (SameParentChain(parent_names, *parent_chain) &&
+ !ProcessEntry(entry, callback))
+ return;
+ }
+}
+
+bool DebugNamesDWARFIndex::SameParentChain(
+ llvm::ArrayRef<llvm::StringRef> parent_names,
+ llvm::ArrayRef<DebugNames::Entry> parent_entries) const {
+
+ if (parent_entries.size() != parent_names.size())
+ return false;
+
+ auto SameAsEntryATName = [this](llvm::StringRef name,
+ const DebugNames::Entry &entry) {
+ // Peek at the AT_name of `entry` and test equality to `name`.
+ auto maybe_dieoffset = entry.getDIEUnitOffset();
+ if (!maybe_dieoffset)
+ return false;
+ DWARFUnit *unit = GetNonSkeletonUnit(entry);
+ if (!unit)
+ return false;
+ return name == unit->PeekDIEName(unit->GetOffset() + *maybe_dieoffset);
+ };
+
+ // If the AT_name of any parent fails to match the expected name, we don't
+ // have a match.
+ for (auto [parent_name, parent_entry] :
+ llvm::zip_equal(parent_names, parent_entries))
+ if (!SameAsEntryATName(parent_name, parent_entry))
+ return false;
+ return true;
+}
+
+void DebugNamesDWARFIndex::GetTypes(
+ ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
+ for (const DebugNames::Entry &entry :
+ m_debug_names_up->equal_range(name.GetStringRef())) {
+ if (isType(entry.tag())) {
+ if (!ProcessEntry(entry, callback))
+ return;
+ }
+ }
+
+ m_fallback.GetTypes(name, callback);
+}
+
+void DebugNamesDWARFIndex::GetTypes(
+ const DWARFDeclContext &context,
+ llvm::function_ref<bool(DWARFDIE die)> callback) {
+ auto name = context[0].name;
+ for (const DebugNames::Entry &entry : m_debug_names_up->equal_range(name)) {
+ if (entry.tag() == context[0].tag) {
+ if (!ProcessEntry(entry, callback))
+ return;
+ }
+ }
+
+ m_fallback.GetTypes(context, callback);
+}
+
+void DebugNamesDWARFIndex::GetNamespaces(
+ ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
+ for (const DebugNames::Entry &entry :
+ m_debug_names_up->equal_range(name.GetStringRef())) {
+ lldb_private::dwarf::Tag entry_tag = entry.tag();
+ if (entry_tag == DW_TAG_namespace ||
+ entry_tag == DW_TAG_imported_declaration) {
+ if (!ProcessEntry(entry, callback))
+ return;
+ }
+ }
+
+ m_fallback.GetNamespaces(name, callback);
+}
+
+void DebugNamesDWARFIndex::GetFunctions(
+ const Module::LookupInfo &lookup_info, SymbolFileDWARF &dwarf,
+ const CompilerDeclContext &parent_decl_ctx,
+ llvm::function_ref<bool(DWARFDIE die)> callback) {
+ ConstString name = lookup_info.GetLookupName();
+ std::set<DWARFDebugInfoEntry *> seen;
+ for (const DebugNames::Entry &entry :
+ m_debug_names_up->equal_range(name.GetStringRef())) {
+ Tag tag = entry.tag();
+ if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine)
+ continue;
+
+ if (DWARFDIE die = GetDIE(entry)) {
+ if (!ProcessFunctionDIE(lookup_info, die, parent_decl_ctx,
+ [&](DWARFDIE die) {
+ if (!seen.insert(die.GetDIE()).second)
+ return true;
+ return callback(die);
+ }))
+ return;
+ }
+ }
+
+ m_fallback.GetFunctions(lookup_info, dwarf, parent_decl_ctx, callback);
+}
+
+void DebugNamesDWARFIndex::GetFunctions(
+ const RegularExpression &regex,
+ llvm::function_ref<bool(DWARFDIE die)> callback) {
+ for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
+ for (DebugNames::NameTableEntry nte: ni) {
+ if (!regex.Execute(nte.getString()))
+ continue;
+
+ uint64_t entry_offset = nte.getEntryOffset();
+ llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
+ for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
+ Tag tag = entry_or->tag();
+ if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine)
+ continue;
+
+ if (!ProcessEntry(*entry_or, callback))
+ return;
+ }
+ MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
+ }
+ }
+
+ m_fallback.GetFunctions(regex, callback);
+}
+
+void DebugNamesDWARFIndex::Dump(Stream &s) {
+ m_fallback.Dump(s);
+
+ std::string data;
+ llvm::raw_string_ostream os(data);
+ m_debug_names_up->dump(os);
+ s.PutCString(os.str());
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h
new file mode 100644
index 000000000000..cb15c1d4f994
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h
@@ -0,0 +1,133 @@
+//===-- DebugNamesDWARFIndex.h ---------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DEBUGNAMESDWARFINDEX_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DEBUGNAMESDWARFINDEX_H
+
+#include "Plugins/SymbolFile/DWARF/DWARFIndex.h"
+#include "Plugins/SymbolFile/DWARF/ManualDWARFIndex.h"
+#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
+#include "lldb/Utility/ConstString.h"
+#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
+#include <optional>
+
+namespace lldb_private::plugin {
+namespace dwarf {
+class DebugNamesDWARFIndex : public DWARFIndex {
+public:
+ static llvm::Expected<std::unique_ptr<DebugNamesDWARFIndex>>
+ Create(Module &module, DWARFDataExtractor debug_names,
+ DWARFDataExtractor debug_str, SymbolFileDWARF &dwarf);
+
+ void Preload() override { m_fallback.Preload(); }
+
+ void
+ GetGlobalVariables(ConstString basename,
+ llvm::function_ref<bool(DWARFDIE die)> callback) override;
+ void
+ GetGlobalVariables(const RegularExpression &regex,
+ llvm::function_ref<bool(DWARFDIE die)> callback) override;
+ void
+ GetGlobalVariables(DWARFUnit &cu,
+ llvm::function_ref<bool(DWARFDIE die)> callback) override;
+ void
+ GetObjCMethods(ConstString class_name,
+ llvm::function_ref<bool(DWARFDIE die)> callback) override {}
+ void GetCompleteObjCClass(
+ ConstString class_name, bool must_be_implementation,
+ llvm::function_ref<bool(DWARFDIE die)> callback) override;
+
+ /// Uses DWARF5's IDX_parent fields, when available, to speed up this query.
+ void GetFullyQualifiedType(
+ const DWARFDeclContext &context,
+ llvm::function_ref<bool(DWARFDIE die)> callback) override;
+ void GetTypes(ConstString name,
+ llvm::function_ref<bool(DWARFDIE die)> callback) override;
+ void GetTypes(const DWARFDeclContext &context,
+ llvm::function_ref<bool(DWARFDIE die)> callback) override;
+ void GetNamespaces(ConstString name,
+ llvm::function_ref<bool(DWARFDIE die)> callback) override;
+ void GetFunctions(const Module::LookupInfo &lookup_info,
+ SymbolFileDWARF &dwarf,
+ const CompilerDeclContext &parent_decl_ctx,
+ llvm::function_ref<bool(DWARFDIE die)> callback) override;
+ void GetFunctions(const RegularExpression &regex,
+ llvm::function_ref<bool(DWARFDIE die)> callback) override;
+
+ void Dump(Stream &s) override;
+
+private:
+ DebugNamesDWARFIndex(Module &module,
+ std::unique_ptr<llvm::DWARFDebugNames> debug_names_up,
+ DWARFDataExtractor debug_names_data,
+ DWARFDataExtractor debug_str_data,
+ SymbolFileDWARF &dwarf)
+ : DWARFIndex(module), m_debug_info(dwarf.DebugInfo()),
+ m_debug_names_data(debug_names_data), m_debug_str_data(debug_str_data),
+ m_debug_names_up(std::move(debug_names_up)),
+ m_fallback(module, dwarf, GetUnits(*m_debug_names_up),
+ GetTypeUnitSignatures(*m_debug_names_up)) {}
+
+ DWARFDebugInfo &m_debug_info;
+
+ // LLVM DWARFDebugNames will hold a non-owning reference to this data, so keep
+ // track of the ownership here.
+ DWARFDataExtractor m_debug_names_data;
+ DWARFDataExtractor m_debug_str_data;
+
+ using DebugNames = llvm::DWARFDebugNames;
+ std::unique_ptr<DebugNames> m_debug_names_up;
+ ManualDWARFIndex m_fallback;
+
+ DWARFUnit *GetNonSkeletonUnit(const DebugNames::Entry &entry) const;
+ DWARFDIE GetDIE(const DebugNames::Entry &entry) const;
+
+ /// Checks if an entry is a foreign TU and fetch the type unit.
+ ///
+ /// This function checks if the DebugNames::Entry refers to a foreign TU and
+ /// returns an optional with a value of the \a entry is a foreign type unit
+ /// entry. A valid pointer will be returned if this entry is from a .dwo file
+ /// or if it is from a .dwp file and it matches the type unit's originating
+ /// .dwo file by verifying that the DW_TAG_type_unit DIE has a DW_AT_dwo_name
+ /// that matches the DWO name from the originating skeleton compile unit.
+ ///
+ /// \param[in] entry
+ /// The accelerator table entry to check.
+ ///
+ /// \returns
+ /// A std::optional that has a value if this entry represents a foreign type
+ /// unit. If the pointer is valid, then we were able to find and match the
+ /// entry to the type unit in the .dwo or .dwp file. The returned value can
+ /// have a valid, yet contain NULL in the following cases:
+ /// - we were not able to load the .dwo file (missing or DWO ID mismatch)
+ /// - we were able to load the .dwp file, but the type units DWO name
+ /// doesn't match the originating skeleton compile unit's entry
+ /// Returns std::nullopt if this entry is not a foreign type unit entry.
+ std::optional<DWARFTypeUnit *>
+ GetForeignTypeUnit(const DebugNames::Entry &entry) const;
+
+ bool ProcessEntry(const DebugNames::Entry &entry,
+ llvm::function_ref<bool(DWARFDIE die)> callback);
+
+ /// Returns true if `parent_entries` have identical names to `parent_names`.
+ bool SameParentChain(llvm::ArrayRef<llvm::StringRef> parent_names,
+ llvm::ArrayRef<DebugNames::Entry> parent_entries) const;
+
+ static void MaybeLogLookupError(llvm::Error error,
+ const DebugNames::NameIndex &ni,
+ llvm::StringRef name);
+
+ static llvm::DenseSet<dw_offset_t> GetUnits(const DebugNames &debug_names);
+ static llvm::DenseSet<uint64_t>
+ GetTypeUnitSignatures(const DebugNames &debug_names);
+};
+
+} // namespace dwarf
+} // namespace lldb_private::plugin
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DEBUGNAMESDWARFINDEX_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp
new file mode 100644
index 000000000000..795355b57a06
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp
@@ -0,0 +1,38 @@
+//===-- LogChannelDWARF.cpp -----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "LogChannelDWARF.h"
+
+using namespace lldb_private;
+
+static constexpr Log::Category g_categories[] = {
+ {{"comp"},
+ {"log struct/union/class type completions"},
+ DWARFLog::TypeCompletion},
+ {{"info"}, {"log the parsing of .debug_info"}, DWARFLog::DebugInfo},
+ {{"line"}, {"log the parsing of .debug_line"}, DWARFLog::DebugLine},
+ {{"lookups"},
+ {"log any lookups that happen by name, regex, or address"},
+ DWARFLog::Lookups},
+ {{"map"},
+ {"log insertions of object files into DWARF debug maps"},
+ DWARFLog::DebugMap},
+ {{"split"}, {"log split DWARF related activities"}, DWARFLog::SplitDwarf},
+};
+
+static Log::Channel g_channel(g_categories, DWARFLog::DebugInfo);
+
+template <> Log::Channel &lldb_private::LogChannelFor<DWARFLog>() {
+ return g_channel;
+}
+
+void LogChannelDWARF::Initialize() {
+ Log::Register("dwarf", g_channel);
+}
+
+void LogChannelDWARF::Terminate() { Log::Unregister("dwarf"); }
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h
new file mode 100644
index 000000000000..7f254a1162bd
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h
@@ -0,0 +1,37 @@
+//===-- LogChannelDWARF.h ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_LOGCHANNELDWARF_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_LOGCHANNELDWARF_H
+
+#include "lldb/Utility/Log.h"
+#include "llvm/ADT/BitmaskEnum.h"
+
+namespace lldb_private {
+
+enum class DWARFLog : Log::MaskType {
+ DebugInfo = Log::ChannelFlag<0>,
+ DebugLine = Log::ChannelFlag<1>,
+ DebugMap = Log::ChannelFlag<2>,
+ Lookups = Log::ChannelFlag<3>,
+ TypeCompletion = Log::ChannelFlag<4>,
+ SplitDwarf = Log::ChannelFlag<5>,
+ LLVM_MARK_AS_BITMASK_ENUM(TypeCompletion)
+};
+LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
+
+class LogChannelDWARF {
+public:
+ static void Initialize();
+ static void Terminate();
+};
+
+template <> Log::Channel &LogChannelFor<DWARFLog>();
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_LOGCHANNELDWARF_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp
new file mode 100644
index 000000000000..d581d3773ab2
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp
@@ -0,0 +1,740 @@
+//===-- ManualDWARFIndex.cpp ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/SymbolFile/DWARF/ManualDWARFIndex.h"
+#include "Plugins/Language/ObjC/ObjCLanguage.h"
+#include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h"
+#include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h"
+#include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h"
+#include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h"
+#include "lldb/Core/DataFileCache.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Progress.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Utility/DataEncoder.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/Timer.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/ThreadPool.h"
+#include <optional>
+
+using namespace lldb_private;
+using namespace lldb;
+using namespace lldb_private::dwarf;
+using namespace lldb_private::plugin::dwarf;
+
+void ManualDWARFIndex::Index() {
+ if (m_indexed)
+ return;
+ m_indexed = true;
+
+ ElapsedTime elapsed(m_index_time);
+ LLDB_SCOPED_TIMERF("%p", static_cast<void *>(m_dwarf));
+ if (LoadFromCache()) {
+ m_dwarf->SetDebugInfoIndexWasLoadedFromCache();
+ return;
+ }
+
+ DWARFDebugInfo &main_info = m_dwarf->DebugInfo();
+ SymbolFileDWARFDwo *dwp_dwarf = m_dwarf->GetDwpSymbolFile().get();
+ DWARFDebugInfo *dwp_info = dwp_dwarf ? &dwp_dwarf->DebugInfo() : nullptr;
+
+ std::vector<DWARFUnit *> units_to_index;
+ units_to_index.reserve(main_info.GetNumUnits() +
+ (dwp_info ? dwp_info->GetNumUnits() : 0));
+
+ // Process all units in the main file, as well as any type units in the dwp
+ // file. Type units in dwo files are handled when we reach the dwo file in
+ // IndexUnit.
+ for (size_t U = 0; U < main_info.GetNumUnits(); ++U) {
+ DWARFUnit *unit = main_info.GetUnitAtIndex(U);
+ if (unit && m_units_to_avoid.count(unit->GetOffset()) == 0)
+ units_to_index.push_back(unit);
+ }
+ if (dwp_info && dwp_info->ContainsTypeUnits()) {
+ for (size_t U = 0; U < dwp_info->GetNumUnits(); ++U) {
+ if (auto *tu =
+ llvm::dyn_cast<DWARFTypeUnit>(dwp_info->GetUnitAtIndex(U))) {
+ if (!m_type_sigs_to_avoid.contains(tu->GetTypeHash()))
+ units_to_index.push_back(tu);
+ }
+ }
+ }
+
+ if (units_to_index.empty())
+ return;
+
+ StreamString module_desc;
+ m_module.GetDescription(module_desc.AsRawOstream(),
+ lldb::eDescriptionLevelBrief);
+
+ // Include 2 passes per unit to index for extracting DIEs from the unit and
+ // indexing the unit, and then 8 extra entries for finalizing each index set.
+ const uint64_t total_progress = units_to_index.size() * 2 + 8;
+ Progress progress("Manually indexing DWARF", module_desc.GetData(),
+ total_progress);
+
+ std::vector<IndexSet> sets(units_to_index.size());
+
+ // Keep memory down by clearing DIEs for any units if indexing
+ // caused us to load the unit's DIEs.
+ std::vector<std::optional<DWARFUnit::ScopedExtractDIEs>> clear_cu_dies(
+ units_to_index.size());
+ auto parser_fn = [&](size_t cu_idx) {
+ IndexUnit(*units_to_index[cu_idx], dwp_dwarf, sets[cu_idx]);
+ progress.Increment();
+ };
+
+ auto extract_fn = [&](size_t cu_idx) {
+ clear_cu_dies[cu_idx] = units_to_index[cu_idx]->ExtractDIEsScoped();
+ progress.Increment();
+ };
+
+ // Share one thread pool across operations to avoid the overhead of
+ // recreating the threads.
+ llvm::ThreadPoolTaskGroup task_group(Debugger::GetThreadPool());
+
+ // Create a task runner that extracts dies for each DWARF unit in a
+ // separate thread.
+ // First figure out which units didn't have their DIEs already
+ // parsed and remember this. If no DIEs were parsed prior to this index
+ // function call, we are going to want to clear the CU dies after we are
+ // done indexing to make sure we don't pull in all DWARF dies, but we need
+ // to wait until all units have been indexed in case a DIE in one
+ // unit refers to another and the indexes accesses those DIEs.
+ for (size_t i = 0; i < units_to_index.size(); ++i)
+ task_group.async(extract_fn, i);
+ task_group.wait();
+
+ // Now create a task runner that can index each DWARF unit in a
+ // separate thread so we can index quickly.
+ for (size_t i = 0; i < units_to_index.size(); ++i)
+ task_group.async(parser_fn, i);
+ task_group.wait();
+
+ auto finalize_fn = [this, &sets, &progress](NameToDIE(IndexSet::*index)) {
+ NameToDIE &result = m_set.*index;
+ for (auto &set : sets)
+ result.Append(set.*index);
+ result.Finalize();
+ progress.Increment();
+ };
+
+ task_group.async(finalize_fn, &IndexSet::function_basenames);
+ task_group.async(finalize_fn, &IndexSet::function_fullnames);
+ task_group.async(finalize_fn, &IndexSet::function_methods);
+ task_group.async(finalize_fn, &IndexSet::function_selectors);
+ task_group.async(finalize_fn, &IndexSet::objc_class_selectors);
+ task_group.async(finalize_fn, &IndexSet::globals);
+ task_group.async(finalize_fn, &IndexSet::types);
+ task_group.async(finalize_fn, &IndexSet::namespaces);
+ task_group.wait();
+
+ SaveToCache();
+}
+
+void ManualDWARFIndex::IndexUnit(DWARFUnit &unit, SymbolFileDWARFDwo *dwp,
+ IndexSet &set) {
+ Log *log = GetLog(DWARFLog::Lookups);
+
+ if (log) {
+ m_module.LogMessage(
+ log, "ManualDWARFIndex::IndexUnit for unit at .debug_info[{0:x16}]",
+ unit.GetOffset());
+ }
+
+ const LanguageType cu_language = SymbolFileDWARF::GetLanguage(unit);
+
+ // First check if the unit has a DWO ID. If it does then we only want to index
+ // the .dwo file or nothing at all. If we have a compile unit where we can't
+ // locate the .dwo/.dwp file we don't want to index anything from the skeleton
+ // compile unit because it is usally has no children unless
+ // -fsplit-dwarf-inlining was used at compile time. This option will add a
+ // copy of all DW_TAG_subprogram and any contained DW_TAG_inline_subroutine
+ // DIEs so that symbolication will still work in the absence of the .dwo/.dwp
+ // file, but the functions have no return types and all arguments and locals
+ // have been removed. So we don't want to index any of these hacked up
+ // function types. Types can still exist in the skeleton compile unit DWARF
+ // though as some functions have template parameter types and other things
+ // that cause extra copies of types to be included, but we should find these
+ // types in the .dwo file only as methods could have return types removed and
+ // we don't have to index incomplete types from the skeleton compile unit.
+ if (unit.GetDWOId()) {
+ // Index the .dwo or dwp instead of the skeleton unit.
+ if (SymbolFileDWARFDwo *dwo_symbol_file = unit.GetDwoSymbolFile()) {
+ // Type units in a dwp file are indexed separately, so we just need to
+ // process the split unit here. However, if the split unit is in a dwo
+ // file, then we need to process type units here.
+ if (dwo_symbol_file == dwp) {
+ IndexUnitImpl(unit.GetNonSkeletonUnit(), cu_language, set);
+ } else {
+ DWARFDebugInfo &dwo_info = dwo_symbol_file->DebugInfo();
+ for (size_t i = 0; i < dwo_info.GetNumUnits(); ++i)
+ IndexUnitImpl(*dwo_info.GetUnitAtIndex(i), cu_language, set);
+ }
+ return;
+ }
+ // This was a DWARF5 skeleton CU and the .dwo file couldn't be located.
+ if (unit.GetVersion() >= 5 && unit.IsSkeletonUnit())
+ return;
+
+ // Either this is a DWARF 4 + fission CU with the .dwo file
+ // missing, or it's a -gmodules pch or pcm. Try to detect the
+ // latter by checking whether the first DIE is a DW_TAG_module.
+ // If it's a pch/pcm, continue indexing it.
+ if (unit.GetDIE(unit.GetFirstDIEOffset()).GetFirstChild().Tag() !=
+ llvm::dwarf::DW_TAG_module)
+ return;
+ }
+ // We have a normal compile unit which we want to index.
+ IndexUnitImpl(unit, cu_language, set);
+}
+
+void ManualDWARFIndex::IndexUnitImpl(DWARFUnit &unit,
+ const LanguageType cu_language,
+ IndexSet &set) {
+ for (const DWARFDebugInfoEntry &die : unit.dies()) {
+ const dw_tag_t tag = die.Tag();
+
+ switch (tag) {
+ case DW_TAG_array_type:
+ case DW_TAG_base_type:
+ case DW_TAG_class_type:
+ case DW_TAG_constant:
+ case DW_TAG_enumeration_type:
+ case DW_TAG_inlined_subroutine:
+ case DW_TAG_namespace:
+ case DW_TAG_imported_declaration:
+ case DW_TAG_string_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_subprogram:
+ case DW_TAG_subroutine_type:
+ case DW_TAG_typedef:
+ case DW_TAG_union_type:
+ case DW_TAG_unspecified_type:
+ case DW_TAG_variable:
+ break;
+
+ default:
+ continue;
+ }
+
+ const char *name = nullptr;
+ const char *mangled_cstr = nullptr;
+ bool is_declaration = false;
+ bool has_address = false;
+ bool has_location_or_const_value = false;
+ bool is_global_or_static_variable = false;
+
+ DWARFFormValue specification_die_form;
+ DWARFAttributes attributes = die.GetAttributes(&unit);
+ for (size_t i = 0; i < attributes.Size(); ++i) {
+ dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ switch (attr) {
+ default:
+ break;
+ case DW_AT_name:
+ if (attributes.ExtractFormValueAtIndex(i, form_value))
+ name = form_value.AsCString();
+ break;
+
+ case DW_AT_declaration:
+ if (attributes.ExtractFormValueAtIndex(i, form_value))
+ is_declaration = form_value.Unsigned() != 0;
+ break;
+
+ case DW_AT_MIPS_linkage_name:
+ case DW_AT_linkage_name:
+ if (attributes.ExtractFormValueAtIndex(i, form_value))
+ mangled_cstr = form_value.AsCString();
+ break;
+
+ case DW_AT_low_pc:
+ case DW_AT_high_pc:
+ case DW_AT_ranges:
+ has_address = true;
+ break;
+
+ case DW_AT_entry_pc:
+ has_address = true;
+ break;
+
+ case DW_AT_location:
+ case DW_AT_const_value:
+ has_location_or_const_value = true;
+ is_global_or_static_variable = die.IsGlobalOrStaticScopeVariable();
+
+ break;
+
+ case DW_AT_specification:
+ if (attributes.ExtractFormValueAtIndex(i, form_value))
+ specification_die_form = form_value;
+ break;
+ }
+ }
+
+ DIERef ref = *DWARFDIE(&unit, &die).GetDIERef();
+ switch (tag) {
+ case DW_TAG_inlined_subroutine:
+ case DW_TAG_subprogram:
+ if (has_address) {
+ if (name) {
+ bool is_objc_method = false;
+ if (cu_language == eLanguageTypeObjC ||
+ cu_language == eLanguageTypeObjC_plus_plus) {
+ std::optional<const ObjCLanguage::MethodName> objc_method =
+ ObjCLanguage::MethodName::Create(name, true);
+ if (objc_method) {
+ is_objc_method = true;
+ ConstString class_name_with_category(
+ objc_method->GetClassNameWithCategory());
+ ConstString objc_selector_name(objc_method->GetSelector());
+ ConstString objc_fullname_no_category_name(
+ objc_method->GetFullNameWithoutCategory().c_str());
+ ConstString class_name_no_category(objc_method->GetClassName());
+ set.function_fullnames.Insert(ConstString(name), ref);
+ if (class_name_with_category)
+ set.objc_class_selectors.Insert(class_name_with_category, ref);
+ if (class_name_no_category &&
+ class_name_no_category != class_name_with_category)
+ set.objc_class_selectors.Insert(class_name_no_category, ref);
+ if (objc_selector_name)
+ set.function_selectors.Insert(objc_selector_name, ref);
+ if (objc_fullname_no_category_name)
+ set.function_fullnames.Insert(objc_fullname_no_category_name,
+ ref);
+ }
+ }
+ // If we have a mangled name, then the DW_AT_name attribute is
+ // usually the method name without the class or any parameters
+ bool is_method = DWARFDIE(&unit, &die).IsMethod();
+
+ if (is_method)
+ set.function_methods.Insert(ConstString(name), ref);
+ else
+ set.function_basenames.Insert(ConstString(name), ref);
+
+ if (!is_method && !mangled_cstr && !is_objc_method)
+ set.function_fullnames.Insert(ConstString(name), ref);
+ }
+ if (mangled_cstr) {
+ // Make sure our mangled name isn't the same string table entry as
+ // our name. If it starts with '_', then it is ok, else compare the
+ // string to make sure it isn't the same and we don't end up with
+ // duplicate entries
+ if (name && name != mangled_cstr &&
+ ((mangled_cstr[0] == '_') ||
+ (::strcmp(name, mangled_cstr) != 0))) {
+ set.function_fullnames.Insert(ConstString(mangled_cstr), ref);
+ }
+ }
+ }
+ break;
+
+ case DW_TAG_array_type:
+ case DW_TAG_base_type:
+ case DW_TAG_class_type:
+ case DW_TAG_constant:
+ case DW_TAG_enumeration_type:
+ case DW_TAG_string_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_subroutine_type:
+ case DW_TAG_typedef:
+ case DW_TAG_union_type:
+ case DW_TAG_unspecified_type:
+ if (name && !is_declaration)
+ set.types.Insert(ConstString(name), ref);
+ if (mangled_cstr && !is_declaration)
+ set.types.Insert(ConstString(mangled_cstr), ref);
+ break;
+
+ case DW_TAG_namespace:
+ case DW_TAG_imported_declaration:
+ if (name)
+ set.namespaces.Insert(ConstString(name), ref);
+ break;
+
+ case DW_TAG_variable:
+ if (name && has_location_or_const_value && is_global_or_static_variable) {
+ set.globals.Insert(ConstString(name), ref);
+ // Be sure to include variables by their mangled and demangled names if
+ // they have any since a variable can have a basename "i", a mangled
+ // named "_ZN12_GLOBAL__N_11iE" and a demangled mangled name
+ // "(anonymous namespace)::i"...
+
+ // Make sure our mangled name isn't the same string table entry as our
+ // name. If it starts with '_', then it is ok, else compare the string
+ // to make sure it isn't the same and we don't end up with duplicate
+ // entries
+ if (mangled_cstr && name != mangled_cstr &&
+ ((mangled_cstr[0] == '_') || (::strcmp(name, mangled_cstr) != 0))) {
+ set.globals.Insert(ConstString(mangled_cstr), ref);
+ }
+ }
+ break;
+
+ default:
+ continue;
+ }
+ }
+}
+
+void ManualDWARFIndex::GetGlobalVariables(
+ ConstString basename, llvm::function_ref<bool(DWARFDIE die)> callback) {
+ Index();
+ m_set.globals.Find(basename,
+ DIERefCallback(callback, basename.GetStringRef()));
+}
+
+void ManualDWARFIndex::GetGlobalVariables(
+ const RegularExpression &regex,
+ llvm::function_ref<bool(DWARFDIE die)> callback) {
+ Index();
+ m_set.globals.Find(regex, DIERefCallback(callback, regex.GetText()));
+}
+
+void ManualDWARFIndex::GetGlobalVariables(
+ DWARFUnit &unit, llvm::function_ref<bool(DWARFDIE die)> callback) {
+ Index();
+ m_set.globals.FindAllEntriesForUnit(unit, DIERefCallback(callback));
+}
+
+void ManualDWARFIndex::GetObjCMethods(
+ ConstString class_name, llvm::function_ref<bool(DWARFDIE die)> callback) {
+ Index();
+ m_set.objc_class_selectors.Find(
+ class_name, DIERefCallback(callback, class_name.GetStringRef()));
+}
+
+void ManualDWARFIndex::GetCompleteObjCClass(
+ ConstString class_name, bool must_be_implementation,
+ llvm::function_ref<bool(DWARFDIE die)> callback) {
+ Index();
+ m_set.types.Find(class_name,
+ DIERefCallback(callback, class_name.GetStringRef()));
+}
+
+void ManualDWARFIndex::GetTypes(
+ ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
+ Index();
+ m_set.types.Find(name, DIERefCallback(callback, name.GetStringRef()));
+}
+
+void ManualDWARFIndex::GetTypes(
+ const DWARFDeclContext &context,
+ llvm::function_ref<bool(DWARFDIE die)> callback) {
+ Index();
+ auto name = context[0].name;
+ m_set.types.Find(ConstString(name),
+ DIERefCallback(callback, llvm::StringRef(name)));
+}
+
+void ManualDWARFIndex::GetNamespaces(
+ ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
+ Index();
+ m_set.namespaces.Find(name, DIERefCallback(callback, name.GetStringRef()));
+}
+
+void ManualDWARFIndex::GetFunctions(
+ const Module::LookupInfo &lookup_info, SymbolFileDWARF &dwarf,
+ const CompilerDeclContext &parent_decl_ctx,
+ llvm::function_ref<bool(DWARFDIE die)> callback) {
+ Index();
+ ConstString name = lookup_info.GetLookupName();
+ FunctionNameType name_type_mask = lookup_info.GetNameTypeMask();
+
+ if (name_type_mask & eFunctionNameTypeFull) {
+ if (!m_set.function_fullnames.Find(
+ name, DIERefCallback(
+ [&](DWARFDIE die) {
+ if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx,
+ die))
+ return true;
+ return callback(die);
+ },
+ name.GetStringRef())))
+ return;
+ }
+ if (name_type_mask & eFunctionNameTypeBase) {
+ if (!m_set.function_basenames.Find(
+ name, DIERefCallback(
+ [&](DWARFDIE die) {
+ if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx,
+ die))
+ return true;
+ return callback(die);
+ },
+ name.GetStringRef())))
+ return;
+ }
+
+ if (name_type_mask & eFunctionNameTypeMethod && !parent_decl_ctx.IsValid()) {
+ if (!m_set.function_methods.Find(
+ name, DIERefCallback(callback, name.GetStringRef())))
+ return;
+ }
+
+ if (name_type_mask & eFunctionNameTypeSelector &&
+ !parent_decl_ctx.IsValid()) {
+ if (!m_set.function_selectors.Find(
+ name, DIERefCallback(callback, name.GetStringRef())))
+ return;
+ }
+}
+
+void ManualDWARFIndex::GetFunctions(
+ const RegularExpression &regex,
+ llvm::function_ref<bool(DWARFDIE die)> callback) {
+ Index();
+
+ if (!m_set.function_basenames.Find(regex,
+ DIERefCallback(callback, regex.GetText())))
+ return;
+ if (!m_set.function_fullnames.Find(regex,
+ DIERefCallback(callback, regex.GetText())))
+ return;
+}
+
+void ManualDWARFIndex::Dump(Stream &s) {
+ s.Format("Manual DWARF index for ({0}) '{1:F}':",
+ m_module.GetArchitecture().GetArchitectureName(),
+ m_module.GetObjectFile()->GetFileSpec());
+ s.Printf("\nFunction basenames:\n");
+ m_set.function_basenames.Dump(&s);
+ s.Printf("\nFunction fullnames:\n");
+ m_set.function_fullnames.Dump(&s);
+ s.Printf("\nFunction methods:\n");
+ m_set.function_methods.Dump(&s);
+ s.Printf("\nFunction selectors:\n");
+ m_set.function_selectors.Dump(&s);
+ s.Printf("\nObjective-C class selectors:\n");
+ m_set.objc_class_selectors.Dump(&s);
+ s.Printf("\nGlobals and statics:\n");
+ m_set.globals.Dump(&s);
+ s.Printf("\nTypes:\n");
+ m_set.types.Dump(&s);
+ s.Printf("\nNamespaces:\n");
+ m_set.namespaces.Dump(&s);
+}
+
+constexpr llvm::StringLiteral kIdentifierManualDWARFIndex("DIDX");
+// Define IDs for the different tables when encoding and decoding the
+// ManualDWARFIndex NameToDIE objects so we can avoid saving any empty maps.
+enum DataID {
+ kDataIDFunctionBasenames = 1u,
+ kDataIDFunctionFullnames,
+ kDataIDFunctionMethods,
+ kDataIDFunctionSelectors,
+ kDataIDFunctionObjcClassSelectors,
+ kDataIDGlobals,
+ kDataIDTypes,
+ kDataIDNamespaces,
+ kDataIDEnd = 255u,
+
+};
+
+// Version 2 changes the encoding of DIERef objects used in the DWARF manual
+// index name tables. See DIERef class for details.
+constexpr uint32_t CURRENT_CACHE_VERSION = 2;
+
+bool ManualDWARFIndex::IndexSet::Decode(const DataExtractor &data,
+ lldb::offset_t *offset_ptr) {
+ StringTableReader strtab;
+ // We now decode the string table for all strings in the data cache file.
+ if (!strtab.Decode(data, offset_ptr))
+ return false;
+
+ llvm::StringRef identifier((const char *)data.GetData(offset_ptr, 4), 4);
+ if (identifier != kIdentifierManualDWARFIndex)
+ return false;
+ const uint32_t version = data.GetU32(offset_ptr);
+ if (version != CURRENT_CACHE_VERSION)
+ return false;
+
+ bool done = false;
+ while (!done) {
+ switch (data.GetU8(offset_ptr)) {
+ default:
+ // If we got here, this is not expected, we expect the data IDs to match
+ // one of the values from the DataID enumeration.
+ return false;
+ case kDataIDFunctionBasenames:
+ if (!function_basenames.Decode(data, offset_ptr, strtab))
+ return false;
+ break;
+ case kDataIDFunctionFullnames:
+ if (!function_fullnames.Decode(data, offset_ptr, strtab))
+ return false;
+ break;
+ case kDataIDFunctionMethods:
+ if (!function_methods.Decode(data, offset_ptr, strtab))
+ return false;
+ break;
+ case kDataIDFunctionSelectors:
+ if (!function_selectors.Decode(data, offset_ptr, strtab))
+ return false;
+ break;
+ case kDataIDFunctionObjcClassSelectors:
+ if (!objc_class_selectors.Decode(data, offset_ptr, strtab))
+ return false;
+ break;
+ case kDataIDGlobals:
+ if (!globals.Decode(data, offset_ptr, strtab))
+ return false;
+ break;
+ case kDataIDTypes:
+ if (!types.Decode(data, offset_ptr, strtab))
+ return false;
+ break;
+ case kDataIDNamespaces:
+ if (!namespaces.Decode(data, offset_ptr, strtab))
+ return false;
+ break;
+ case kDataIDEnd:
+ // We got to the end of our NameToDIE encodings.
+ done = true;
+ break;
+ }
+ }
+ // Success!
+ return true;
+}
+
+void ManualDWARFIndex::IndexSet::Encode(DataEncoder &encoder) const {
+ ConstStringTable strtab;
+
+ // Encoder the DWARF index into a separate encoder first. This allows us
+ // gather all of the strings we willl need in "strtab" as we will need to
+ // write the string table out before the symbol table.
+ DataEncoder index_encoder(encoder.GetByteOrder(),
+ encoder.GetAddressByteSize());
+
+ index_encoder.AppendData(kIdentifierManualDWARFIndex);
+ // Encode the data version.
+ index_encoder.AppendU32(CURRENT_CACHE_VERSION);
+
+ if (!function_basenames.IsEmpty()) {
+ index_encoder.AppendU8(kDataIDFunctionBasenames);
+ function_basenames.Encode(index_encoder, strtab);
+ }
+ if (!function_fullnames.IsEmpty()) {
+ index_encoder.AppendU8(kDataIDFunctionFullnames);
+ function_fullnames.Encode(index_encoder, strtab);
+ }
+ if (!function_methods.IsEmpty()) {
+ index_encoder.AppendU8(kDataIDFunctionMethods);
+ function_methods.Encode(index_encoder, strtab);
+ }
+ if (!function_selectors.IsEmpty()) {
+ index_encoder.AppendU8(kDataIDFunctionSelectors);
+ function_selectors.Encode(index_encoder, strtab);
+ }
+ if (!objc_class_selectors.IsEmpty()) {
+ index_encoder.AppendU8(kDataIDFunctionObjcClassSelectors);
+ objc_class_selectors.Encode(index_encoder, strtab);
+ }
+ if (!globals.IsEmpty()) {
+ index_encoder.AppendU8(kDataIDGlobals);
+ globals.Encode(index_encoder, strtab);
+ }
+ if (!types.IsEmpty()) {
+ index_encoder.AppendU8(kDataIDTypes);
+ types.Encode(index_encoder, strtab);
+ }
+ if (!namespaces.IsEmpty()) {
+ index_encoder.AppendU8(kDataIDNamespaces);
+ namespaces.Encode(index_encoder, strtab);
+ }
+ index_encoder.AppendU8(kDataIDEnd);
+
+ // Now that all strings have been gathered, we will emit the string table.
+ strtab.Encode(encoder);
+ // Followed by the symbol table data.
+ encoder.AppendData(index_encoder.GetData());
+}
+
+bool ManualDWARFIndex::Decode(const DataExtractor &data,
+ lldb::offset_t *offset_ptr,
+ bool &signature_mismatch) {
+ signature_mismatch = false;
+ CacheSignature signature;
+ if (!signature.Decode(data, offset_ptr))
+ return false;
+ if (CacheSignature(m_dwarf->GetObjectFile()) != signature) {
+ signature_mismatch = true;
+ return false;
+ }
+ IndexSet set;
+ if (!set.Decode(data, offset_ptr))
+ return false;
+ m_set = std::move(set);
+ return true;
+}
+
+bool ManualDWARFIndex::Encode(DataEncoder &encoder) const {
+ CacheSignature signature(m_dwarf->GetObjectFile());
+ if (!signature.Encode(encoder))
+ return false;
+ m_set.Encode(encoder);
+ return true;
+}
+
+std::string ManualDWARFIndex::GetCacheKey() {
+ std::string key;
+ llvm::raw_string_ostream strm(key);
+ // DWARF Index can come from different object files for the same module. A
+ // module can have one object file as the main executable and might have
+ // another object file in a separate symbol file, or we might have a .dwo file
+ // that claims its module is the main executable.
+ ObjectFile *objfile = m_dwarf->GetObjectFile();
+ strm << objfile->GetModule()->GetCacheKey() << "-dwarf-index-"
+ << llvm::format_hex(objfile->GetCacheHash(), 10);
+ return strm.str();
+}
+
+bool ManualDWARFIndex::LoadFromCache() {
+ DataFileCache *cache = Module::GetIndexCache();
+ if (!cache)
+ return false;
+ ObjectFile *objfile = m_dwarf->GetObjectFile();
+ if (!objfile)
+ return false;
+ std::unique_ptr<llvm::MemoryBuffer> mem_buffer_up =
+ cache->GetCachedData(GetCacheKey());
+ if (!mem_buffer_up)
+ return false;
+ DataExtractor data(mem_buffer_up->getBufferStart(),
+ mem_buffer_up->getBufferSize(),
+ endian::InlHostByteOrder(),
+ objfile->GetAddressByteSize());
+ bool signature_mismatch = false;
+ lldb::offset_t offset = 0;
+ const bool result = Decode(data, &offset, signature_mismatch);
+ if (signature_mismatch)
+ cache->RemoveCacheFile(GetCacheKey());
+ return result;
+}
+
+void ManualDWARFIndex::SaveToCache() {
+ DataFileCache *cache = Module::GetIndexCache();
+ if (!cache)
+ return; // Caching is not enabled.
+ ObjectFile *objfile = m_dwarf->GetObjectFile();
+ if (!objfile)
+ return;
+ DataEncoder file(endian::InlHostByteOrder(), objfile->GetAddressByteSize());
+ // Encode will return false if the object file doesn't have anything to make
+ // a signature from.
+ if (Encode(file)) {
+ if (cache->SetCachedData(GetCacheKey(), file.GetData()))
+ m_dwarf->SetDebugInfoIndexWasSavedToCache();
+ }
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h
new file mode 100644
index 000000000000..d8c4a22ab21f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h
@@ -0,0 +1,183 @@
+//===-- ManualDWARFIndex.h --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_MANUALDWARFINDEX_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_MANUALDWARFINDEX_H
+
+#include "Plugins/SymbolFile/DWARF/DWARFIndex.h"
+#include "Plugins/SymbolFile/DWARF/NameToDIE.h"
+#include "llvm/ADT/DenseSet.h"
+
+namespace lldb_private::plugin {
+namespace dwarf {
+class DWARFDebugInfo;
+class SymbolFileDWARFDwo;
+
+class ManualDWARFIndex : public DWARFIndex {
+public:
+ ManualDWARFIndex(Module &module, SymbolFileDWARF &dwarf,
+ llvm::DenseSet<dw_offset_t> units_to_avoid = {},
+ llvm::DenseSet<uint64_t> type_sigs_to_avoid = {})
+ : DWARFIndex(module), m_dwarf(&dwarf),
+ m_units_to_avoid(std::move(units_to_avoid)),
+ m_type_sigs_to_avoid(std::move(type_sigs_to_avoid)) {}
+
+ void Preload() override { Index(); }
+
+ void
+ GetGlobalVariables(ConstString basename,
+ llvm::function_ref<bool(DWARFDIE die)> callback) override;
+ void
+ GetGlobalVariables(const RegularExpression &regex,
+ llvm::function_ref<bool(DWARFDIE die)> callback) override;
+ void
+ GetGlobalVariables(DWARFUnit &unit,
+ llvm::function_ref<bool(DWARFDIE die)> callback) override;
+ void GetObjCMethods(ConstString class_name,
+ llvm::function_ref<bool(DWARFDIE die)> callback) override;
+ void GetCompleteObjCClass(
+ ConstString class_name, bool must_be_implementation,
+ llvm::function_ref<bool(DWARFDIE die)> callback) override;
+ void GetTypes(ConstString name,
+ llvm::function_ref<bool(DWARFDIE die)> callback) override;
+ void GetTypes(const DWARFDeclContext &context,
+ llvm::function_ref<bool(DWARFDIE die)> callback) override;
+ void GetNamespaces(ConstString name,
+ llvm::function_ref<bool(DWARFDIE die)> callback) override;
+ void GetFunctions(const Module::LookupInfo &lookup_info,
+ SymbolFileDWARF &dwarf,
+ const CompilerDeclContext &parent_decl_ctx,
+ llvm::function_ref<bool(DWARFDIE die)> callback) override;
+ void GetFunctions(const RegularExpression &regex,
+ llvm::function_ref<bool(DWARFDIE die)> callback) override;
+
+ void Dump(Stream &s) override;
+
+ // Make IndexSet public so we can unit test the encoding and decoding logic.
+ struct IndexSet {
+ NameToDIE function_basenames;
+ NameToDIE function_fullnames;
+ NameToDIE function_methods;
+ NameToDIE function_selectors;
+ NameToDIE objc_class_selectors;
+ NameToDIE globals;
+ NameToDIE types;
+ NameToDIE namespaces;
+ bool Decode(const DataExtractor &data, lldb::offset_t *offset_ptr);
+ void Encode(DataEncoder &encoder) const;
+ bool operator==(const IndexSet &rhs) const {
+ return function_basenames == rhs.function_basenames &&
+ function_fullnames == rhs.function_fullnames &&
+ function_methods == rhs.function_methods &&
+ function_selectors == rhs.function_selectors &&
+ objc_class_selectors == rhs.objc_class_selectors &&
+ globals == rhs.globals && types == rhs.types &&
+ namespaces == rhs.namespaces;
+ }
+ };
+
+private:
+ void Index();
+
+ /// Decode a serialized version of this object from data.
+ ///
+ /// \param data
+ /// The decoder object that references the serialized data.
+ ///
+ /// \param offset_ptr
+ /// A pointer that contains the offset from which the data will be decoded
+ /// from that gets updated as data gets decoded.
+ ///
+ /// \param strtab
+ /// All strings in cache files are put into string tables for efficiency
+ /// and cache file size reduction. Strings are stored as uint32_t string
+ /// table offsets in the cache data.
+ bool Decode(const DataExtractor &data, lldb::offset_t *offset_ptr,
+ bool &signature_mismatch);
+
+ /// Encode this object into a data encoder object.
+ ///
+ /// This allows this object to be serialized to disk.
+ ///
+ /// \param encoder
+ /// A data encoder object that serialized bytes will be encoded into.
+ ///
+ /// \param strtab
+ /// All strings in cache files are put into string tables for efficiency
+ /// and cache file size reduction. Strings are stored as uint32_t string
+ /// table offsets in the cache data.
+ ///
+ /// \return
+ /// True if the symbol table's object file can generate a valid signature
+ /// and all data for the symbol table was encoded, false otherwise.
+ bool Encode(DataEncoder &encoder) const;
+
+ /// Get the cache key string for this symbol table.
+ ///
+ /// The cache key must start with the module's cache key and is followed
+ /// by information that indicates this key is for caching the symbol table
+ /// contents and should also include the has of the object file. A module can
+ /// be represented by an ObjectFile object for the main executable, but can
+ /// also have a symbol file that is from the same or a different object file.
+ /// This means we might have two symbol tables cached in the index cache, one
+ /// for the main executable and one for the symbol file.
+ ///
+ /// \return
+ /// The unique cache key used to save and retrieve data from the index
+ /// cache.
+ std::string GetCacheKey();
+
+ /// Save the symbol table data out into a cache.
+ ///
+ /// The symbol table will only be saved to a cache file if caching is enabled.
+ ///
+ /// We cache the contents of the symbol table since symbol tables in LLDB take
+ /// some time to initialize. This is due to the many sources for data that are
+ /// used to create a symbol table:
+ /// - standard symbol table
+ /// - dynamic symbol table (ELF)
+ /// - compressed debug info sections
+ /// - unwind information
+ /// - function pointers found in runtimes for global constructor/destructors
+ /// - other sources.
+ /// All of the above sources are combined and one symbol table results after
+ /// all sources have been considered.
+ void SaveToCache();
+
+ /// Load the symbol table from the index cache.
+ ///
+ /// Quickly load the finalized symbol table from the index cache. This saves
+ /// time when the debugger starts up. The index cache file for the symbol
+ /// table has the modification time set to the same time as the main module.
+ /// If the cache file exists and the modification times match, we will load
+ /// the symbol table from the serlized cache file.
+ ///
+ /// \return
+ /// True if the symbol table was successfully loaded from the index cache,
+ /// false if the symbol table wasn't cached or was out of date.
+ bool LoadFromCache();
+
+ void IndexUnit(DWARFUnit &unit, SymbolFileDWARFDwo *dwp, IndexSet &set);
+
+ static void IndexUnitImpl(DWARFUnit &unit,
+ const lldb::LanguageType cu_language,
+ IndexSet &set);
+
+ /// The DWARF file which we are indexing.
+ SymbolFileDWARF *m_dwarf;
+ /// Which dwarf units should we skip while building the index.
+ llvm::DenseSet<dw_offset_t> m_units_to_avoid;
+ llvm::DenseSet<uint64_t> m_type_sigs_to_avoid;
+
+ IndexSet m_set;
+ bool m_indexed = false;
+};
+} // namespace dwarf
+} // namespace lldb_private::plugin
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_MANUALDWARFINDEX_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp
new file mode 100644
index 000000000000..44d90648700c
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp
@@ -0,0 +1,151 @@
+//===-- NameToDIE.cpp -----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NameToDIE.h"
+#include "DWARFUnit.h"
+#include "lldb/Core/DataFileCache.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/DataEncoder.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StreamString.h"
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::plugin::dwarf;
+
+void NameToDIE::Finalize() {
+ m_map.Sort(std::less<DIERef>());
+ m_map.SizeToFit();
+}
+
+void NameToDIE::Insert(ConstString name, const DIERef &die_ref) {
+ m_map.Append(name, die_ref);
+}
+
+bool NameToDIE::Find(ConstString name,
+ llvm::function_ref<bool(DIERef ref)> callback) const {
+ for (const auto &entry : m_map.equal_range(name))
+ if (!callback(entry.value))
+ return false;
+ return true;
+}
+
+bool NameToDIE::Find(const RegularExpression &regex,
+ llvm::function_ref<bool(DIERef ref)> callback) const {
+ for (const auto &entry : m_map)
+ if (regex.Execute(entry.cstring.GetCString())) {
+ if (!callback(entry.value))
+ return false;
+ }
+ return true;
+}
+
+void NameToDIE::FindAllEntriesForUnit(
+ DWARFUnit &s_unit, llvm::function_ref<bool(DIERef ref)> callback) const {
+ const DWARFUnit &ns_unit = s_unit.GetNonSkeletonUnit();
+ const uint32_t size = m_map.GetSize();
+ for (uint32_t i = 0; i < size; ++i) {
+ const DIERef &die_ref = m_map.GetValueAtIndexUnchecked(i);
+ if (ns_unit.GetSymbolFileDWARF().GetFileIndex() == die_ref.file_index() &&
+ ns_unit.GetDebugSection() == die_ref.section() &&
+ ns_unit.GetOffset() <= die_ref.die_offset() &&
+ die_ref.die_offset() < ns_unit.GetNextUnitOffset()) {
+ if (!callback(die_ref))
+ return;
+ }
+ }
+}
+
+void NameToDIE::Dump(Stream *s) {
+ const uint32_t size = m_map.GetSize();
+ for (uint32_t i = 0; i < size; ++i) {
+ s->Format("{0} \"{1}\"\n", m_map.GetValueAtIndexUnchecked(i),
+ m_map.GetCStringAtIndexUnchecked(i));
+ }
+}
+
+void NameToDIE::ForEach(
+ std::function<bool(ConstString name, const DIERef &die_ref)> const
+ &callback) const {
+ const uint32_t size = m_map.GetSize();
+ for (uint32_t i = 0; i < size; ++i) {
+ if (!callback(m_map.GetCStringAtIndexUnchecked(i),
+ m_map.GetValueAtIndexUnchecked(i)))
+ break;
+ }
+}
+
+void NameToDIE::Append(const NameToDIE &other) {
+ const uint32_t size = other.m_map.GetSize();
+ for (uint32_t i = 0; i < size; ++i) {
+ m_map.Append(other.m_map.GetCStringAtIndexUnchecked(i),
+ other.m_map.GetValueAtIndexUnchecked(i));
+ }
+}
+
+constexpr llvm::StringLiteral kIdentifierNameToDIE("N2DI");
+
+bool NameToDIE::Decode(const DataExtractor &data, lldb::offset_t *offset_ptr,
+ const StringTableReader &strtab) {
+ m_map.Clear();
+ llvm::StringRef identifier((const char *)data.GetData(offset_ptr, 4), 4);
+ if (identifier != kIdentifierNameToDIE)
+ return false;
+ const uint32_t count = data.GetU32(offset_ptr);
+ m_map.Reserve(count);
+ for (uint32_t i = 0; i < count; ++i) {
+ llvm::StringRef str(strtab.Get(data.GetU32(offset_ptr)));
+ // No empty strings allowed in the name to DIE maps.
+ if (str.empty())
+ return false;
+ if (std::optional<DIERef> die_ref = DIERef::Decode(data, offset_ptr))
+ m_map.Append(ConstString(str), *die_ref);
+ else
+ return false;
+ }
+ // We must sort the UniqueCStringMap after decoding it since it is a vector
+ // of UniqueCStringMap::Entry objects which contain a ConstString and type T.
+ // ConstString objects are sorted by "const char *" and then type T and
+ // the "const char *" are point values that will depend on the order in which
+ // ConstString objects are created and in which of the 256 string pools they
+ // are created in. So after we decode all of the entries, we must sort the
+ // name map to ensure name lookups succeed. If we encode and decode within
+ // the same process we wouldn't need to sort, so unit testing didn't catch
+ // this issue when first checked in.
+ m_map.Sort(std::less<DIERef>());
+ return true;
+}
+
+void NameToDIE::Encode(DataEncoder &encoder, ConstStringTable &strtab) const {
+ encoder.AppendData(kIdentifierNameToDIE);
+ encoder.AppendU32(m_map.GetSize());
+ for (const auto &entry : m_map) {
+ // Make sure there are no empty strings.
+ assert((bool)entry.cstring);
+ encoder.AppendU32(strtab.Add(entry.cstring));
+ entry.value.Encode(encoder);
+ }
+}
+
+bool NameToDIE::operator==(const NameToDIE &rhs) const {
+ const size_t size = m_map.GetSize();
+ if (size != rhs.m_map.GetSize())
+ return false;
+ for (size_t i = 0; i < size; ++i) {
+ if (m_map.GetCStringAtIndex(i) != rhs.m_map.GetCStringAtIndex(i))
+ return false;
+ if (m_map.GetValueRefAtIndexUnchecked(i) !=
+ rhs.m_map.GetValueRefAtIndexUnchecked(i))
+ return false;
+ }
+ return true;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.h
new file mode 100644
index 000000000000..90eac1fa3733
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.h
@@ -0,0 +1,94 @@
+//===-- NameToDIE.h ---------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_NAMETODIE_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_NAMETODIE_H
+
+#include <functional>
+
+#include "DIERef.h"
+#include "lldb/Core/UniqueCStringMap.h"
+#include "lldb/Core/dwarf.h"
+#include "lldb/lldb-defines.h"
+
+namespace lldb_private::plugin {
+namespace dwarf {
+class DWARFUnit;
+
+class NameToDIE {
+public:
+ NameToDIE() : m_map() {}
+
+ ~NameToDIE() = default;
+
+ void Dump(Stream *s);
+
+ void Insert(ConstString name, const DIERef &die_ref);
+
+ void Append(const NameToDIE &other);
+
+ void Finalize();
+
+ bool Find(ConstString name,
+ llvm::function_ref<bool(DIERef ref)> callback) const;
+
+ bool Find(const RegularExpression &regex,
+ llvm::function_ref<bool(DIERef ref)> callback) const;
+
+ /// \a unit must be the skeleton unit if possible, not GetNonSkeletonUnit().
+ void
+ FindAllEntriesForUnit(DWARFUnit &unit,
+ llvm::function_ref<bool(DIERef ref)> callback) const;
+
+ void
+ ForEach(std::function<bool(ConstString name, const DIERef &die_ref)> const
+ &callback) const;
+
+ /// Decode a serialized version of this object from data.
+ ///
+ /// \param data
+ /// The decoder object that references the serialized data.
+ ///
+ /// \param offset_ptr
+ /// A pointer that contains the offset from which the data will be decoded
+ /// from that gets updated as data gets decoded.
+ ///
+ /// \param strtab
+ /// All strings in cache files are put into string tables for efficiency
+ /// and cache file size reduction. Strings are stored as uint32_t string
+ /// table offsets in the cache data.
+ bool Decode(const DataExtractor &data, lldb::offset_t *offset_ptr,
+ const StringTableReader &strtab);
+
+ /// Encode this object into a data encoder object.
+ ///
+ /// This allows this object to be serialized to disk.
+ ///
+ /// \param encoder
+ /// A data encoder object that serialized bytes will be encoded into.
+ ///
+ /// \param strtab
+ /// All strings in cache files are put into string tables for efficiency
+ /// and cache file size reduction. Strings are stored as uint32_t string
+ /// table offsets in the cache data.
+ void Encode(DataEncoder &encoder, ConstStringTable &strtab) const;
+
+ /// Used for unit testing the encoding and decoding.
+ bool operator==(const NameToDIE &rhs) const;
+
+ bool IsEmpty() const { return m_map.IsEmpty(); }
+
+ void Clear() { m_map.Clear(); }
+
+protected:
+ UniqueCStringMap<DIERef> m_map;
+};
+} // namespace dwarf
+} // namespace lldb_private::plugin
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_NAMETODIE_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
new file mode 100644
index 000000000000..7cd3a33c7de5
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -0,0 +1,4484 @@
+//===-- SymbolFileDWARF.cpp -----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolFileDWARF.h"
+
+#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/Threading.h"
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Progress.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/Scalar.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/StructuredData.h"
+#include "lldb/Utility/Timer.h"
+
+#include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h"
+#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
+
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/Host.h"
+
+#include "lldb/Interpreter/OptionValueFileSpecList.h"
+#include "lldb/Interpreter/OptionValueProperties.h"
+
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
+#include "Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "lldb/Symbol/Block.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/CompilerDecl.h"
+#include "lldb/Symbol/CompilerDeclContext.h"
+#include "lldb/Symbol/DebugMacros.h"
+#include "lldb/Symbol/LineTable.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Symbol/TypeMap.h"
+#include "lldb/Symbol/TypeSystem.h"
+#include "lldb/Symbol/VariableList.h"
+
+#include "lldb/Target/Language.h"
+#include "lldb/Target/Target.h"
+
+#include "AppleDWARFIndex.h"
+#include "DWARFASTParser.h"
+#include "DWARFASTParserClang.h"
+#include "DWARFCompileUnit.h"
+#include "DWARFDebugAranges.h"
+#include "DWARFDebugInfo.h"
+#include "DWARFDebugMacro.h"
+#include "DWARFDebugRanges.h"
+#include "DWARFDeclContext.h"
+#include "DWARFFormValue.h"
+#include "DWARFTypeUnit.h"
+#include "DWARFUnit.h"
+#include "DebugNamesDWARFIndex.h"
+#include "LogChannelDWARF.h"
+#include "ManualDWARFIndex.h"
+#include "SymbolFileDWARFDebugMap.h"
+#include "SymbolFileDWARFDwo.h"
+
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FormatVariadic.h"
+
+#include <algorithm>
+#include <map>
+#include <memory>
+#include <optional>
+
+#include <cctype>
+#include <cstring>
+
+//#define ENABLE_DEBUG_PRINTF // COMMENT OUT THIS LINE PRIOR TO CHECKIN
+
+#ifdef ENABLE_DEBUG_PRINTF
+#include <cstdio>
+#define DEBUG_PRINTF(fmt, ...) printf(fmt, __VA_ARGS__)
+#else
+#define DEBUG_PRINTF(fmt, ...)
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::dwarf;
+using namespace lldb_private::plugin::dwarf;
+
+LLDB_PLUGIN_DEFINE(SymbolFileDWARF)
+
+char SymbolFileDWARF::ID;
+
+namespace {
+
+#define LLDB_PROPERTIES_symbolfiledwarf
+#include "SymbolFileDWARFProperties.inc"
+
+enum {
+#define LLDB_PROPERTIES_symbolfiledwarf
+#include "SymbolFileDWARFPropertiesEnum.inc"
+};
+
+class PluginProperties : public Properties {
+public:
+ static llvm::StringRef GetSettingName() {
+ return SymbolFileDWARF::GetPluginNameStatic();
+ }
+
+ PluginProperties() {
+ m_collection_sp = std::make_shared<OptionValueProperties>(GetSettingName());
+ m_collection_sp->Initialize(g_symbolfiledwarf_properties);
+ }
+
+ bool IgnoreFileIndexes() const {
+ return GetPropertyAtIndexAs<bool>(ePropertyIgnoreIndexes, false);
+ }
+};
+
+} // namespace
+
+bool IsStructOrClassTag(llvm::dwarf::Tag Tag) {
+ return Tag == llvm::dwarf::Tag::DW_TAG_class_type ||
+ Tag == llvm::dwarf::Tag::DW_TAG_structure_type;
+}
+
+static PluginProperties &GetGlobalPluginProperties() {
+ static PluginProperties g_settings;
+ return g_settings;
+}
+
+static const llvm::DWARFDebugLine::LineTable *
+ParseLLVMLineTable(DWARFContext &context, llvm::DWARFDebugLine &line,
+ dw_offset_t line_offset, dw_offset_t unit_offset) {
+ Log *log = GetLog(DWARFLog::DebugInfo);
+
+ llvm::DWARFDataExtractor data = context.getOrLoadLineData().GetAsLLVMDWARF();
+ llvm::DWARFContext &ctx = context.GetAsLLVM();
+ llvm::Expected<const llvm::DWARFDebugLine::LineTable *> line_table =
+ line.getOrParseLineTable(
+ data, line_offset, ctx, nullptr, [&](llvm::Error e) {
+ LLDB_LOG_ERROR(
+ log, std::move(e),
+ "SymbolFileDWARF::ParseLineTable failed to parse: {0}");
+ });
+
+ if (!line_table) {
+ LLDB_LOG_ERROR(log, line_table.takeError(),
+ "SymbolFileDWARF::ParseLineTable failed to parse: {0}");
+ return nullptr;
+ }
+ return *line_table;
+}
+
+static bool ParseLLVMLineTablePrologue(DWARFContext &context,
+ llvm::DWARFDebugLine::Prologue &prologue,
+ dw_offset_t line_offset,
+ dw_offset_t unit_offset) {
+ Log *log = GetLog(DWARFLog::DebugInfo);
+ bool success = true;
+ llvm::DWARFDataExtractor data = context.getOrLoadLineData().GetAsLLVMDWARF();
+ llvm::DWARFContext &ctx = context.GetAsLLVM();
+ uint64_t offset = line_offset;
+ llvm::Error error = prologue.parse(
+ data, &offset,
+ [&](llvm::Error e) {
+ success = false;
+ LLDB_LOG_ERROR(log, std::move(e),
+ "SymbolFileDWARF::ParseSupportFiles failed to parse "
+ "line table prologue: {0}");
+ },
+ ctx, nullptr);
+ if (error) {
+ LLDB_LOG_ERROR(log, std::move(error),
+ "SymbolFileDWARF::ParseSupportFiles failed to parse line "
+ "table prologue: {0}");
+ return false;
+ }
+ return success;
+}
+
+static std::optional<std::string>
+GetFileByIndex(const llvm::DWARFDebugLine::Prologue &prologue, size_t idx,
+ llvm::StringRef compile_dir, FileSpec::Style style) {
+ // Try to get an absolute path first.
+ std::string abs_path;
+ auto absolute = llvm::DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath;
+ if (prologue.getFileNameByIndex(idx, compile_dir, absolute, abs_path, style))
+ return std::move(abs_path);
+
+ // Otherwise ask for a relative path.
+ std::string rel_path;
+ auto relative = llvm::DILineInfoSpecifier::FileLineInfoKind::RawValue;
+ if (!prologue.getFileNameByIndex(idx, compile_dir, relative, rel_path, style))
+ return {};
+ return std::move(rel_path);
+}
+
+static void ParseSupportFilesFromPrologue(
+ SupportFileList &support_files, const lldb::ModuleSP &module,
+ const llvm::DWARFDebugLine::Prologue &prologue, FileSpec::Style style,
+ llvm::StringRef compile_dir = {}) {
+ // Handle the case where there are no files first to avoid having to special
+ // case this later.
+ if (prologue.FileNames.empty())
+ return;
+
+ // Before DWARF v5, the line table indexes were one based.
+ const bool is_one_based = prologue.getVersion() < 5;
+ const size_t file_names = prologue.FileNames.size();
+ const size_t first_file_idx = is_one_based ? 1 : 0;
+ const size_t last_file_idx = is_one_based ? file_names : file_names - 1;
+
+ // Add a dummy entry to ensure the support file list indices match those we
+ // get from the debug info and line tables.
+ if (is_one_based)
+ support_files.Append(FileSpec());
+
+ for (size_t idx = first_file_idx; idx <= last_file_idx; ++idx) {
+ std::string remapped_file;
+ if (auto file_path = GetFileByIndex(prologue, idx, compile_dir, style)) {
+ auto entry = prologue.getFileNameEntry(idx);
+ auto source = entry.Source.getAsCString();
+ if (!source)
+ consumeError(source.takeError());
+ else {
+ llvm::StringRef source_ref(*source);
+ if (!source_ref.empty()) {
+ /// Wrap a path for an in-DWARF source file. Lazily write it
+ /// to disk when Materialize() is called.
+ struct LazyDWARFSourceFile : public SupportFile {
+ LazyDWARFSourceFile(const FileSpec &fs, llvm::StringRef source,
+ FileSpec::Style style)
+ : SupportFile(fs), source(source), style(style) {}
+ FileSpec tmp_file;
+ /// The file contents buffer.
+ llvm::StringRef source;
+ /// Deletes the temporary file at the end.
+ std::unique_ptr<llvm::FileRemover> remover;
+ FileSpec::Style style;
+
+ /// Write the file contents to a temporary file.
+ const FileSpec &Materialize() override {
+ if (tmp_file)
+ return tmp_file;
+ llvm::SmallString<0> name;
+ int fd;
+ auto orig_name = m_file_spec.GetFilename().GetStringRef();
+ auto ec = llvm::sys::fs::createTemporaryFile(
+ "", llvm::sys::path::filename(orig_name, style), fd, name);
+ if (ec || fd <= 0) {
+ LLDB_LOG(GetLog(DWARFLog::DebugInfo),
+ "Could not create temporary file");
+ return tmp_file;
+ }
+ remover = std::make_unique<llvm::FileRemover>(name);
+ NativeFile file(fd, File::eOpenOptionWriteOnly, true);
+ size_t num_bytes = source.size();
+ file.Write(source.data(), num_bytes);
+ tmp_file.SetPath(name);
+ return tmp_file;
+ }
+ };
+ support_files.Append(std::make_unique<LazyDWARFSourceFile>(
+ FileSpec(*file_path), *source, style));
+ continue;
+ }
+ }
+ if (auto remapped = module->RemapSourceFile(llvm::StringRef(*file_path)))
+ remapped_file = *remapped;
+ else
+ remapped_file = std::move(*file_path);
+ }
+
+ Checksum checksum;
+ if (prologue.ContentTypes.HasMD5) {
+ const llvm::DWARFDebugLine::FileNameEntry &file_name_entry =
+ prologue.getFileNameEntry(idx);
+ checksum = file_name_entry.Checksum;
+ }
+
+ // Unconditionally add an entry, so the indices match up.
+ support_files.EmplaceBack(FileSpec(remapped_file, style), checksum);
+ }
+}
+
+void SymbolFileDWARF::Initialize() {
+ LogChannelDWARF::Initialize();
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(), CreateInstance,
+ DebuggerInitialize);
+ SymbolFileDWARFDebugMap::Initialize();
+}
+
+void SymbolFileDWARF::DebuggerInitialize(Debugger &debugger) {
+ if (!PluginManager::GetSettingForSymbolFilePlugin(
+ debugger, PluginProperties::GetSettingName())) {
+ const bool is_global_setting = true;
+ PluginManager::CreateSettingForSymbolFilePlugin(
+ debugger, GetGlobalPluginProperties().GetValueProperties(),
+ "Properties for the dwarf symbol-file plug-in.", is_global_setting);
+ }
+}
+
+void SymbolFileDWARF::Terminate() {
+ SymbolFileDWARFDebugMap::Terminate();
+ PluginManager::UnregisterPlugin(CreateInstance);
+ LogChannelDWARF::Terminate();
+}
+
+llvm::StringRef SymbolFileDWARF::GetPluginDescriptionStatic() {
+ return "DWARF and DWARF3 debug symbol file reader.";
+}
+
+SymbolFile *SymbolFileDWARF::CreateInstance(ObjectFileSP objfile_sp) {
+ return new SymbolFileDWARF(std::move(objfile_sp),
+ /*dwo_section_list*/ nullptr);
+}
+
+TypeList &SymbolFileDWARF::GetTypeList() {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ if (SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile())
+ return debug_map_symfile->GetTypeList();
+ return SymbolFileCommon::GetTypeList();
+}
+void SymbolFileDWARF::GetTypes(const DWARFDIE &die, dw_offset_t min_die_offset,
+ dw_offset_t max_die_offset, uint32_t type_mask,
+ TypeSet &type_set) {
+ if (die) {
+ const dw_offset_t die_offset = die.GetOffset();
+
+ if (die_offset >= max_die_offset)
+ return;
+
+ if (die_offset >= min_die_offset) {
+ const dw_tag_t tag = die.Tag();
+
+ bool add_type = false;
+
+ switch (tag) {
+ case DW_TAG_array_type:
+ add_type = (type_mask & eTypeClassArray) != 0;
+ break;
+ case DW_TAG_unspecified_type:
+ case DW_TAG_base_type:
+ add_type = (type_mask & eTypeClassBuiltin) != 0;
+ break;
+ case DW_TAG_class_type:
+ add_type = (type_mask & eTypeClassClass) != 0;
+ break;
+ case DW_TAG_structure_type:
+ add_type = (type_mask & eTypeClassStruct) != 0;
+ break;
+ case DW_TAG_union_type:
+ add_type = (type_mask & eTypeClassUnion) != 0;
+ break;
+ case DW_TAG_enumeration_type:
+ add_type = (type_mask & eTypeClassEnumeration) != 0;
+ break;
+ case DW_TAG_subroutine_type:
+ case DW_TAG_subprogram:
+ case DW_TAG_inlined_subroutine:
+ add_type = (type_mask & eTypeClassFunction) != 0;
+ break;
+ case DW_TAG_pointer_type:
+ add_type = (type_mask & eTypeClassPointer) != 0;
+ break;
+ case DW_TAG_rvalue_reference_type:
+ case DW_TAG_reference_type:
+ add_type = (type_mask & eTypeClassReference) != 0;
+ break;
+ case DW_TAG_typedef:
+ add_type = (type_mask & eTypeClassTypedef) != 0;
+ break;
+ case DW_TAG_ptr_to_member_type:
+ add_type = (type_mask & eTypeClassMemberPointer) != 0;
+ break;
+ default:
+ break;
+ }
+
+ if (add_type) {
+ const bool assert_not_being_parsed = true;
+ Type *type = ResolveTypeUID(die, assert_not_being_parsed);
+ if (type)
+ type_set.insert(type);
+ }
+ }
+
+ for (DWARFDIE child_die : die.children()) {
+ GetTypes(child_die, min_die_offset, max_die_offset, type_mask, type_set);
+ }
+ }
+}
+
+void SymbolFileDWARF::GetTypes(SymbolContextScope *sc_scope,
+ TypeClass type_mask, TypeList &type_list)
+
+{
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ TypeSet type_set;
+
+ CompileUnit *comp_unit = nullptr;
+ if (sc_scope)
+ comp_unit = sc_scope->CalculateSymbolContextCompileUnit();
+
+ const auto &get = [&](DWARFUnit *unit) {
+ if (!unit)
+ return;
+ unit = &unit->GetNonSkeletonUnit();
+ GetTypes(unit->DIE(), unit->GetOffset(), unit->GetNextUnitOffset(),
+ type_mask, type_set);
+ };
+ if (comp_unit) {
+ get(GetDWARFCompileUnit(comp_unit));
+ } else {
+ DWARFDebugInfo &info = DebugInfo();
+ const size_t num_cus = info.GetNumUnits();
+ for (size_t cu_idx = 0; cu_idx < num_cus; ++cu_idx)
+ get(info.GetUnitAtIndex(cu_idx));
+ }
+
+ std::set<CompilerType> compiler_type_set;
+ for (Type *type : type_set) {
+ CompilerType compiler_type = type->GetForwardCompilerType();
+ if (compiler_type_set.find(compiler_type) == compiler_type_set.end()) {
+ compiler_type_set.insert(compiler_type);
+ type_list.Insert(type->shared_from_this());
+ }
+ }
+}
+
+// Gets the first parent that is a lexical block, function or inlined
+// subroutine, or compile unit.
+DWARFDIE
+SymbolFileDWARF::GetParentSymbolContextDIE(const DWARFDIE &child_die) {
+ DWARFDIE die;
+ for (die = child_die.GetParent(); die; die = die.GetParent()) {
+ dw_tag_t tag = die.Tag();
+
+ switch (tag) {
+ case DW_TAG_compile_unit:
+ case DW_TAG_partial_unit:
+ case DW_TAG_subprogram:
+ case DW_TAG_inlined_subroutine:
+ case DW_TAG_lexical_block:
+ return die;
+ default:
+ break;
+ }
+ }
+ return DWARFDIE();
+}
+
+SymbolFileDWARF::SymbolFileDWARF(ObjectFileSP objfile_sp,
+ SectionList *dwo_section_list)
+ : SymbolFileCommon(std::move(objfile_sp)), m_debug_map_module_wp(),
+ m_debug_map_symfile(nullptr),
+ m_context(m_objfile_sp->GetModule()->GetSectionList(), dwo_section_list),
+ m_fetched_external_modules(false),
+ m_supports_DW_AT_APPLE_objc_complete_type(eLazyBoolCalculate) {}
+
+SymbolFileDWARF::~SymbolFileDWARF() = default;
+
+static ConstString GetDWARFMachOSegmentName() {
+ static ConstString g_dwarf_section_name("__DWARF");
+ return g_dwarf_section_name;
+}
+
+llvm::DenseMap<lldb::opaque_compiler_type_t, DIERef> &
+SymbolFileDWARF::GetForwardDeclCompilerTypeToDIE() {
+ if (SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile())
+ return debug_map_symfile->GetForwardDeclCompilerTypeToDIE();
+ return m_forward_decl_compiler_type_to_die;
+}
+
+UniqueDWARFASTTypeMap &SymbolFileDWARF::GetUniqueDWARFASTTypeMap() {
+ SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile();
+ if (debug_map_symfile)
+ return debug_map_symfile->GetUniqueDWARFASTTypeMap();
+ else
+ return m_unique_ast_type_map;
+}
+
+llvm::Expected<lldb::TypeSystemSP>
+SymbolFileDWARF::GetTypeSystemForLanguage(LanguageType language) {
+ if (SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile())
+ return debug_map_symfile->GetTypeSystemForLanguage(language);
+
+ auto type_system_or_err =
+ m_objfile_sp->GetModule()->GetTypeSystemForLanguage(language);
+ if (type_system_or_err)
+ if (auto ts = *type_system_or_err)
+ ts->SetSymbolFile(this);
+ return type_system_or_err;
+}
+
+void SymbolFileDWARF::InitializeObject() {
+ Log *log = GetLog(DWARFLog::DebugInfo);
+
+ InitializeFirstCodeAddress();
+
+ if (!GetGlobalPluginProperties().IgnoreFileIndexes()) {
+ StreamString module_desc;
+ GetObjectFile()->GetModule()->GetDescription(module_desc.AsRawOstream(),
+ lldb::eDescriptionLevelBrief);
+ DWARFDataExtractor apple_names, apple_namespaces, apple_types, apple_objc;
+ LoadSectionData(eSectionTypeDWARFAppleNames, apple_names);
+ LoadSectionData(eSectionTypeDWARFAppleNamespaces, apple_namespaces);
+ LoadSectionData(eSectionTypeDWARFAppleTypes, apple_types);
+ LoadSectionData(eSectionTypeDWARFAppleObjC, apple_objc);
+
+ if (apple_names.GetByteSize() > 0 || apple_namespaces.GetByteSize() > 0 ||
+ apple_types.GetByteSize() > 0 || apple_objc.GetByteSize() > 0) {
+ m_index = AppleDWARFIndex::Create(
+ *GetObjectFile()->GetModule(), apple_names, apple_namespaces,
+ apple_types, apple_objc, m_context.getOrLoadStrData());
+
+ if (m_index)
+ return;
+ }
+
+ DWARFDataExtractor debug_names;
+ LoadSectionData(eSectionTypeDWARFDebugNames, debug_names);
+ if (debug_names.GetByteSize() > 0) {
+ Progress progress("Loading DWARF5 index", module_desc.GetData());
+ llvm::Expected<std::unique_ptr<DebugNamesDWARFIndex>> index_or =
+ DebugNamesDWARFIndex::Create(*GetObjectFile()->GetModule(),
+ debug_names,
+ m_context.getOrLoadStrData(), *this);
+ if (index_or) {
+ m_index = std::move(*index_or);
+ return;
+ }
+ LLDB_LOG_ERROR(log, index_or.takeError(),
+ "Unable to read .debug_names data: {0}");
+ }
+ }
+
+ m_index =
+ std::make_unique<ManualDWARFIndex>(*GetObjectFile()->GetModule(), *this);
+}
+
+void SymbolFileDWARF::InitializeFirstCodeAddress() {
+ InitializeFirstCodeAddressRecursive(
+ *m_objfile_sp->GetModule()->GetSectionList());
+ if (m_first_code_address == LLDB_INVALID_ADDRESS)
+ m_first_code_address = 0;
+}
+
+void SymbolFileDWARF::InitializeFirstCodeAddressRecursive(
+ const lldb_private::SectionList &section_list) {
+ for (SectionSP section_sp : section_list) {
+ if (section_sp->GetChildren().GetSize() > 0) {
+ InitializeFirstCodeAddressRecursive(section_sp->GetChildren());
+ } else if (section_sp->GetType() == eSectionTypeCode) {
+ m_first_code_address =
+ std::min(m_first_code_address, section_sp->GetFileAddress());
+ }
+ }
+}
+
+bool SymbolFileDWARF::SupportedVersion(uint16_t version) {
+ return version >= 2 && version <= 5;
+}
+
+static std::set<dw_form_t>
+GetUnsupportedForms(llvm::DWARFDebugAbbrev *debug_abbrev) {
+ if (!debug_abbrev)
+ return {};
+
+ std::set<dw_form_t> unsupported_forms;
+ for (const auto &[_, decl_set] : *debug_abbrev)
+ for (const auto &decl : decl_set)
+ for (const auto &attr : decl.attributes())
+ if (!DWARFFormValue::FormIsSupported(attr.Form))
+ unsupported_forms.insert(attr.Form);
+
+ return unsupported_forms;
+}
+
+uint32_t SymbolFileDWARF::CalculateAbilities() {
+ uint32_t abilities = 0;
+ if (m_objfile_sp != nullptr) {
+ const Section *section = nullptr;
+ const SectionList *section_list = m_objfile_sp->GetSectionList();
+ if (section_list == nullptr)
+ return 0;
+
+ uint64_t debug_abbrev_file_size = 0;
+ uint64_t debug_info_file_size = 0;
+ uint64_t debug_line_file_size = 0;
+
+ section = section_list->FindSectionByName(GetDWARFMachOSegmentName()).get();
+
+ if (section)
+ section_list = &section->GetChildren();
+
+ section =
+ section_list->FindSectionByType(eSectionTypeDWARFDebugInfo, true).get();
+ if (section != nullptr) {
+ debug_info_file_size = section->GetFileSize();
+
+ section =
+ section_list->FindSectionByType(eSectionTypeDWARFDebugAbbrev, true)
+ .get();
+ if (section)
+ debug_abbrev_file_size = section->GetFileSize();
+
+ llvm::DWARFDebugAbbrev *abbrev = DebugAbbrev();
+ std::set<dw_form_t> unsupported_forms = GetUnsupportedForms(abbrev);
+ if (!unsupported_forms.empty()) {
+ StreamString error;
+ error.Printf("unsupported DW_FORM value%s:",
+ unsupported_forms.size() > 1 ? "s" : "");
+ for (auto form : unsupported_forms)
+ error.Printf(" %#x", form);
+ m_objfile_sp->GetModule()->ReportWarning("{0}", error.GetString());
+ return 0;
+ }
+
+ section =
+ section_list->FindSectionByType(eSectionTypeDWARFDebugLine, true)
+ .get();
+ if (section)
+ debug_line_file_size = section->GetFileSize();
+ } else {
+ llvm::StringRef symfile_dir =
+ m_objfile_sp->GetFileSpec().GetDirectory().GetStringRef();
+ if (symfile_dir.contains_insensitive(".dsym")) {
+ if (m_objfile_sp->GetType() == ObjectFile::eTypeDebugInfo) {
+ // We have a dSYM file that didn't have a any debug info. If the
+ // string table has a size of 1, then it was made from an
+ // executable with no debug info, or from an executable that was
+ // stripped.
+ section =
+ section_list->FindSectionByType(eSectionTypeDWARFDebugStr, true)
+ .get();
+ if (section && section->GetFileSize() == 1) {
+ m_objfile_sp->GetModule()->ReportWarning(
+ "empty dSYM file detected, dSYM was created with an "
+ "executable with no debug info.");
+ }
+ }
+ }
+ }
+
+ constexpr uint64_t MaxDebugInfoSize = (1ull) << DW_DIE_OFFSET_MAX_BITSIZE;
+ if (debug_info_file_size >= MaxDebugInfoSize) {
+ m_objfile_sp->GetModule()->ReportWarning(
+ "SymbolFileDWARF can't load this DWARF. It's larger then {0:x+16}",
+ MaxDebugInfoSize);
+ return 0;
+ }
+
+ if (debug_abbrev_file_size > 0 && debug_info_file_size > 0)
+ abilities |= CompileUnits | Functions | Blocks | GlobalVariables |
+ LocalVariables | VariableTypes;
+
+ if (debug_line_file_size > 0)
+ abilities |= LineTables;
+ }
+ return abilities;
+}
+
+void SymbolFileDWARF::LoadSectionData(lldb::SectionType sect_type,
+ DWARFDataExtractor &data) {
+ ModuleSP module_sp(m_objfile_sp->GetModule());
+ const SectionList *section_list = module_sp->GetSectionList();
+ if (!section_list)
+ return;
+
+ SectionSP section_sp(section_list->FindSectionByType(sect_type, true));
+ if (!section_sp)
+ return;
+
+ data.Clear();
+ m_objfile_sp->ReadSectionData(section_sp.get(), data);
+}
+
+llvm::DWARFDebugAbbrev *SymbolFileDWARF::DebugAbbrev() {
+ if (m_abbr)
+ return m_abbr.get();
+
+ const DWARFDataExtractor &debug_abbrev_data = m_context.getOrLoadAbbrevData();
+ if (debug_abbrev_data.GetByteSize() == 0)
+ return nullptr;
+
+ ElapsedTime elapsed(m_parse_time);
+ auto abbr =
+ std::make_unique<llvm::DWARFDebugAbbrev>(debug_abbrev_data.GetAsLLVM());
+ llvm::Error error = abbr->parse();
+ if (error) {
+ Log *log = GetLog(DWARFLog::DebugInfo);
+ LLDB_LOG_ERROR(log, std::move(error),
+ "Unable to read .debug_abbrev section: {0}");
+ return nullptr;
+ }
+
+ m_abbr = std::move(abbr);
+ return m_abbr.get();
+}
+
+DWARFDebugInfo &SymbolFileDWARF::DebugInfo() {
+ llvm::call_once(m_info_once_flag, [&] {
+ LLDB_SCOPED_TIMER();
+
+ m_info = std::make_unique<DWARFDebugInfo>(*this, m_context);
+ });
+ return *m_info;
+}
+
+DWARFCompileUnit *SymbolFileDWARF::GetDWARFCompileUnit(CompileUnit *comp_unit) {
+ if (!comp_unit)
+ return nullptr;
+
+ // The compile unit ID is the index of the DWARF unit.
+ DWARFUnit *dwarf_cu = DebugInfo().GetUnitAtIndex(comp_unit->GetID());
+ if (dwarf_cu && dwarf_cu->GetLLDBCompUnit() == nullptr)
+ dwarf_cu->SetLLDBCompUnit(comp_unit);
+
+ // It must be DWARFCompileUnit when it created a CompileUnit.
+ return llvm::cast_or_null<DWARFCompileUnit>(dwarf_cu);
+}
+
+DWARFDebugRanges *SymbolFileDWARF::GetDebugRanges() {
+ if (!m_ranges) {
+ LLDB_SCOPED_TIMER();
+
+ if (m_context.getOrLoadRangesData().GetByteSize() > 0)
+ m_ranges = std::make_unique<DWARFDebugRanges>();
+
+ if (m_ranges)
+ m_ranges->Extract(m_context);
+ }
+ return m_ranges.get();
+}
+
+/// Make an absolute path out of \p file_spec and remap it using the
+/// module's source remapping dictionary.
+static void MakeAbsoluteAndRemap(FileSpec &file_spec, DWARFUnit &dwarf_cu,
+ const ModuleSP &module_sp) {
+ if (!file_spec)
+ return;
+ // If we have a full path to the compile unit, we don't need to
+ // resolve the file. This can be expensive e.g. when the source
+ // files are NFS mounted.
+ file_spec.MakeAbsolute(dwarf_cu.GetCompilationDirectory());
+
+ if (auto remapped_file = module_sp->RemapSourceFile(file_spec.GetPath()))
+ file_spec.SetFile(*remapped_file, FileSpec::Style::native);
+}
+
+/// Return the DW_AT_(GNU_)dwo_name.
+static const char *GetDWOName(DWARFCompileUnit &dwarf_cu,
+ const DWARFDebugInfoEntry &cu_die) {
+ const char *dwo_name =
+ cu_die.GetAttributeValueAsString(&dwarf_cu, DW_AT_GNU_dwo_name, nullptr);
+ if (!dwo_name)
+ dwo_name =
+ cu_die.GetAttributeValueAsString(&dwarf_cu, DW_AT_dwo_name, nullptr);
+ return dwo_name;
+}
+
+lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) {
+ CompUnitSP cu_sp;
+ CompileUnit *comp_unit = dwarf_cu.GetLLDBCompUnit();
+ if (comp_unit) {
+ // We already parsed this compile unit, had out a shared pointer to it
+ cu_sp = comp_unit->shared_from_this();
+ } else {
+ if (GetDebugMapSymfile()) {
+ // Let the debug map create the compile unit
+ cu_sp = m_debug_map_symfile->GetCompileUnit(this, dwarf_cu);
+ dwarf_cu.SetLLDBCompUnit(cu_sp.get());
+ } else {
+ ModuleSP module_sp(m_objfile_sp->GetModule());
+ if (module_sp) {
+ auto initialize_cu = [&](lldb::SupportFileSP support_file_sp,
+ LanguageType cu_language,
+ SupportFileList &&support_files = {}) {
+ BuildCuTranslationTable();
+ cu_sp = std::make_shared<CompileUnit>(
+ module_sp, &dwarf_cu, support_file_sp,
+ *GetDWARFUnitIndex(dwarf_cu.GetID()), cu_language,
+ eLazyBoolCalculate, std::move(support_files));
+
+ dwarf_cu.SetLLDBCompUnit(cu_sp.get());
+
+ SetCompileUnitAtIndex(dwarf_cu.GetID(), cu_sp);
+ };
+
+ auto lazy_initialize_cu = [&]() {
+ // If the version is < 5, we can't do lazy initialization.
+ if (dwarf_cu.GetVersion() < 5)
+ return false;
+
+ // If there is no DWO, there is no reason to initialize
+ // lazily; we will do eager initialization in that case.
+ if (GetDebugMapSymfile())
+ return false;
+ const DWARFBaseDIE cu_die = dwarf_cu.GetUnitDIEOnly();
+ if (!cu_die)
+ return false;
+ if (!GetDWOName(dwarf_cu, *cu_die.GetDIE()))
+ return false;
+
+ // With DWARFv5 we can assume that the first support
+ // file is also the name of the compile unit. This
+ // allows us to avoid loading the non-skeleton unit,
+ // which may be in a separate DWO file.
+ SupportFileList support_files;
+ if (!ParseSupportFiles(dwarf_cu, module_sp, support_files))
+ return false;
+ if (support_files.GetSize() == 0)
+ return false;
+ initialize_cu(support_files.GetSupportFileAtIndex(0),
+ eLanguageTypeUnknown, std::move(support_files));
+ return true;
+ };
+
+ if (!lazy_initialize_cu()) {
+ // Eagerly initialize compile unit
+ const DWARFBaseDIE cu_die =
+ dwarf_cu.GetNonSkeletonUnit().GetUnitDIEOnly();
+ if (cu_die) {
+ LanguageType cu_language = SymbolFileDWARF::LanguageTypeFromDWARF(
+ dwarf_cu.GetDWARFLanguageType());
+
+ FileSpec cu_file_spec(cu_die.GetName(), dwarf_cu.GetPathStyle());
+
+ // Path needs to be remapped in this case. In the support files
+ // case ParseSupportFiles takes care of the remapping.
+ MakeAbsoluteAndRemap(cu_file_spec, dwarf_cu, module_sp);
+
+ initialize_cu(std::make_shared<SupportFile>(cu_file_spec),
+ cu_language);
+ }
+ }
+ }
+ }
+ }
+ return cu_sp;
+}
+
+void SymbolFileDWARF::BuildCuTranslationTable() {
+ if (!m_lldb_cu_to_dwarf_unit.empty())
+ return;
+
+ DWARFDebugInfo &info = DebugInfo();
+ if (!info.ContainsTypeUnits()) {
+ // We can use a 1-to-1 mapping. No need to build a translation table.
+ return;
+ }
+ for (uint32_t i = 0, num = info.GetNumUnits(); i < num; ++i) {
+ if (auto *cu = llvm::dyn_cast<DWARFCompileUnit>(info.GetUnitAtIndex(i))) {
+ cu->SetID(m_lldb_cu_to_dwarf_unit.size());
+ m_lldb_cu_to_dwarf_unit.push_back(i);
+ }
+ }
+}
+
+std::optional<uint32_t> SymbolFileDWARF::GetDWARFUnitIndex(uint32_t cu_idx) {
+ BuildCuTranslationTable();
+ if (m_lldb_cu_to_dwarf_unit.empty())
+ return cu_idx;
+ if (cu_idx >= m_lldb_cu_to_dwarf_unit.size())
+ return std::nullopt;
+ return m_lldb_cu_to_dwarf_unit[cu_idx];
+}
+
+uint32_t SymbolFileDWARF::CalculateNumCompileUnits() {
+ BuildCuTranslationTable();
+ return m_lldb_cu_to_dwarf_unit.empty() ? DebugInfo().GetNumUnits()
+ : m_lldb_cu_to_dwarf_unit.size();
+}
+
+CompUnitSP SymbolFileDWARF::ParseCompileUnitAtIndex(uint32_t cu_idx) {
+ ASSERT_MODULE_LOCK(this);
+ if (std::optional<uint32_t> dwarf_idx = GetDWARFUnitIndex(cu_idx)) {
+ if (auto *dwarf_cu = llvm::cast_or_null<DWARFCompileUnit>(
+ DebugInfo().GetUnitAtIndex(*dwarf_idx)))
+ return ParseCompileUnit(*dwarf_cu);
+ }
+ return {};
+}
+
+Function *SymbolFileDWARF::ParseFunction(CompileUnit &comp_unit,
+ const DWARFDIE &die) {
+ ASSERT_MODULE_LOCK(this);
+ if (!die.IsValid())
+ return nullptr;
+
+ auto type_system_or_err = GetTypeSystemForLanguage(GetLanguage(*die.GetCU()));
+ if (auto err = type_system_or_err.takeError()) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Symbols), std::move(err),
+ "Unable to parse function: {0}");
+ return nullptr;
+ }
+ auto ts = *type_system_or_err;
+ if (!ts)
+ return nullptr;
+ DWARFASTParser *dwarf_ast = ts->GetDWARFParser();
+ if (!dwarf_ast)
+ return nullptr;
+
+ DWARFRangeList ranges = die.GetDIE()->GetAttributeAddressRanges(
+ die.GetCU(), /*check_hi_lo_pc=*/true);
+ if (ranges.IsEmpty())
+ return nullptr;
+
+ // Union of all ranges in the function DIE (if the function is
+ // discontiguous)
+ lldb::addr_t lowest_func_addr = ranges.GetMinRangeBase(0);
+ lldb::addr_t highest_func_addr = ranges.GetMaxRangeEnd(0);
+ if (lowest_func_addr == LLDB_INVALID_ADDRESS ||
+ lowest_func_addr >= highest_func_addr ||
+ lowest_func_addr < m_first_code_address)
+ return nullptr;
+
+ ModuleSP module_sp(die.GetModule());
+ AddressRange func_range;
+ func_range.GetBaseAddress().ResolveAddressUsingFileSections(
+ lowest_func_addr, module_sp->GetSectionList());
+ if (!func_range.GetBaseAddress().IsValid())
+ return nullptr;
+
+ func_range.SetByteSize(highest_func_addr - lowest_func_addr);
+ if (!FixupAddress(func_range.GetBaseAddress()))
+ return nullptr;
+
+ return dwarf_ast->ParseFunctionFromDWARF(comp_unit, die, func_range);
+}
+
+ConstString
+SymbolFileDWARF::ConstructFunctionDemangledName(const DWARFDIE &die) {
+ ASSERT_MODULE_LOCK(this);
+ if (!die.IsValid()) {
+ return ConstString();
+ }
+
+ auto type_system_or_err = GetTypeSystemForLanguage(GetLanguage(*die.GetCU()));
+ if (auto err = type_system_or_err.takeError()) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Symbols), std::move(err),
+ "Unable to construct demangled name for function: {0}");
+ return ConstString();
+ }
+
+ auto ts = *type_system_or_err;
+ if (!ts) {
+ LLDB_LOG(GetLog(LLDBLog::Symbols), "Type system no longer live");
+ return ConstString();
+ }
+ DWARFASTParser *dwarf_ast = ts->GetDWARFParser();
+ if (!dwarf_ast)
+ return ConstString();
+
+ return dwarf_ast->ConstructDemangledNameFromDWARF(die);
+}
+
+lldb::addr_t SymbolFileDWARF::FixupAddress(lldb::addr_t file_addr) {
+ SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile();
+ if (debug_map_symfile)
+ return debug_map_symfile->LinkOSOFileAddress(this, file_addr);
+ return file_addr;
+}
+
+bool SymbolFileDWARF::FixupAddress(Address &addr) {
+ SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile();
+ if (debug_map_symfile) {
+ return debug_map_symfile->LinkOSOAddress(addr);
+ }
+ // This is a normal DWARF file, no address fixups need to happen
+ return true;
+}
+lldb::LanguageType SymbolFileDWARF::ParseLanguage(CompileUnit &comp_unit) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ DWARFUnit *dwarf_cu = GetDWARFCompileUnit(&comp_unit);
+ if (dwarf_cu)
+ return GetLanguage(dwarf_cu->GetNonSkeletonUnit());
+ else
+ return eLanguageTypeUnknown;
+}
+
+XcodeSDK SymbolFileDWARF::ParseXcodeSDK(CompileUnit &comp_unit) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ DWARFUnit *dwarf_cu = GetDWARFCompileUnit(&comp_unit);
+ if (!dwarf_cu)
+ return {};
+ const DWARFBaseDIE cu_die = dwarf_cu->GetNonSkeletonUnit().GetUnitDIEOnly();
+ if (!cu_die)
+ return {};
+ const char *sdk = cu_die.GetAttributeValueAsString(DW_AT_APPLE_sdk, nullptr);
+ if (!sdk)
+ return {};
+ const char *sysroot =
+ cu_die.GetAttributeValueAsString(DW_AT_LLVM_sysroot, "");
+ // Register the sysroot path remapping with the module belonging to
+ // the CU as well as the one belonging to the symbol file. The two
+ // would be different if this is an OSO object and module is the
+ // corresponding debug map, in which case both should be updated.
+ ModuleSP module_sp = comp_unit.GetModule();
+ if (module_sp)
+ module_sp->RegisterXcodeSDK(sdk, sysroot);
+
+ ModuleSP local_module_sp = m_objfile_sp->GetModule();
+ if (local_module_sp && local_module_sp != module_sp)
+ local_module_sp->RegisterXcodeSDK(sdk, sysroot);
+
+ return {sdk};
+}
+
+size_t SymbolFileDWARF::ParseFunctions(CompileUnit &comp_unit) {
+ LLDB_SCOPED_TIMER();
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ DWARFUnit *dwarf_cu = GetDWARFCompileUnit(&comp_unit);
+ if (!dwarf_cu)
+ return 0;
+
+ size_t functions_added = 0;
+ dwarf_cu = &dwarf_cu->GetNonSkeletonUnit();
+ for (DWARFDebugInfoEntry &entry : dwarf_cu->dies()) {
+ if (entry.Tag() != DW_TAG_subprogram)
+ continue;
+
+ DWARFDIE die(dwarf_cu, &entry);
+ if (comp_unit.FindFunctionByUID(die.GetID()))
+ continue;
+ if (ParseFunction(comp_unit, die))
+ ++functions_added;
+ }
+ // FixupTypes();
+ return functions_added;
+}
+
+bool SymbolFileDWARF::ForEachExternalModule(
+ CompileUnit &comp_unit,
+ llvm::DenseSet<lldb_private::SymbolFile *> &visited_symbol_files,
+ llvm::function_ref<bool(Module &)> lambda) {
+ // Only visit each symbol file once.
+ if (!visited_symbol_files.insert(this).second)
+ return false;
+
+ UpdateExternalModuleListIfNeeded();
+ for (auto &p : m_external_type_modules) {
+ ModuleSP module = p.second;
+ if (!module)
+ continue;
+
+ // Invoke the action and potentially early-exit.
+ if (lambda(*module))
+ return true;
+
+ for (std::size_t i = 0; i < module->GetNumCompileUnits(); ++i) {
+ auto cu = module->GetCompileUnitAtIndex(i);
+ bool early_exit = cu->ForEachExternalModule(visited_symbol_files, lambda);
+ if (early_exit)
+ return true;
+ }
+ }
+ return false;
+}
+
+bool SymbolFileDWARF::ParseSupportFiles(CompileUnit &comp_unit,
+ SupportFileList &support_files) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ DWARFUnit *dwarf_cu = GetDWARFCompileUnit(&comp_unit);
+ if (!dwarf_cu)
+ return false;
+
+ if (!ParseSupportFiles(*dwarf_cu, comp_unit.GetModule(), support_files))
+ return false;
+
+ return true;
+}
+
+bool SymbolFileDWARF::ParseSupportFiles(DWARFUnit &dwarf_cu,
+ const ModuleSP &module,
+ SupportFileList &support_files) {
+
+ dw_offset_t offset = dwarf_cu.GetLineTableOffset();
+ if (offset == DW_INVALID_OFFSET)
+ return false;
+
+ ElapsedTime elapsed(m_parse_time);
+ llvm::DWARFDebugLine::Prologue prologue;
+ if (!ParseLLVMLineTablePrologue(m_context, prologue, offset,
+ dwarf_cu.GetOffset()))
+ return false;
+
+ std::string comp_dir = dwarf_cu.GetCompilationDirectory().GetPath();
+ ParseSupportFilesFromPrologue(support_files, module, prologue,
+ dwarf_cu.GetPathStyle(), comp_dir);
+ return true;
+}
+
+FileSpec SymbolFileDWARF::GetFile(DWARFUnit &unit, size_t file_idx) {
+ if (auto *dwarf_cu = llvm::dyn_cast<DWARFCompileUnit>(&unit)) {
+ if (CompileUnit *lldb_cu = GetCompUnitForDWARFCompUnit(*dwarf_cu))
+ return lldb_cu->GetSupportFiles().GetFileSpecAtIndex(file_idx);
+ return FileSpec();
+ }
+
+ auto &tu = llvm::cast<DWARFTypeUnit>(unit);
+ if (const SupportFileList *support_files = GetTypeUnitSupportFiles(tu))
+ return support_files->GetFileSpecAtIndex(file_idx);
+ return {};
+}
+
+const SupportFileList *
+SymbolFileDWARF::GetTypeUnitSupportFiles(DWARFTypeUnit &tu) {
+ static SupportFileList empty_list;
+
+ dw_offset_t offset = tu.GetLineTableOffset();
+ if (offset == DW_INVALID_OFFSET ||
+ offset == llvm::DenseMapInfo<dw_offset_t>::getEmptyKey() ||
+ offset == llvm::DenseMapInfo<dw_offset_t>::getTombstoneKey())
+ return nullptr;
+
+ // Many type units can share a line table, so parse the support file list
+ // once, and cache it based on the offset field.
+ auto iter_bool = m_type_unit_support_files.try_emplace(offset);
+ std::unique_ptr<SupportFileList> &list = iter_bool.first->second;
+ if (iter_bool.second) {
+ list = std::make_unique<SupportFileList>();
+ uint64_t line_table_offset = offset;
+ llvm::DWARFDataExtractor data =
+ m_context.getOrLoadLineData().GetAsLLVMDWARF();
+ llvm::DWARFContext &ctx = m_context.GetAsLLVM();
+ llvm::DWARFDebugLine::Prologue prologue;
+ auto report = [](llvm::Error error) {
+ Log *log = GetLog(DWARFLog::DebugInfo);
+ LLDB_LOG_ERROR(log, std::move(error),
+ "SymbolFileDWARF::GetTypeUnitSupportFiles failed to parse "
+ "the line table prologue: {0}");
+ };
+ ElapsedTime elapsed(m_parse_time);
+ llvm::Error error = prologue.parse(data, &line_table_offset, report, ctx);
+ if (error)
+ report(std::move(error));
+ else
+ ParseSupportFilesFromPrologue(*list, GetObjectFile()->GetModule(),
+ prologue, tu.GetPathStyle());
+ }
+ return list.get();
+}
+
+bool SymbolFileDWARF::ParseIsOptimized(CompileUnit &comp_unit) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ DWARFUnit *dwarf_cu = GetDWARFCompileUnit(&comp_unit);
+ if (dwarf_cu)
+ return dwarf_cu->GetNonSkeletonUnit().GetIsOptimized();
+ return false;
+}
+
+bool SymbolFileDWARF::ParseImportedModules(
+ const lldb_private::SymbolContext &sc,
+ std::vector<SourceModule> &imported_modules) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ assert(sc.comp_unit);
+ DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit);
+ if (!dwarf_cu)
+ return false;
+ if (!ClangModulesDeclVendor::LanguageSupportsClangModules(
+ sc.comp_unit->GetLanguage()))
+ return false;
+ UpdateExternalModuleListIfNeeded();
+
+ const DWARFDIE die = dwarf_cu->DIE();
+ if (!die)
+ return false;
+
+ for (DWARFDIE child_die : die.children()) {
+ if (child_die.Tag() != DW_TAG_imported_declaration)
+ continue;
+
+ DWARFDIE module_die = child_die.GetReferencedDIE(DW_AT_import);
+ if (module_die.Tag() != DW_TAG_module)
+ continue;
+
+ if (const char *name =
+ module_die.GetAttributeValueAsString(DW_AT_name, nullptr)) {
+ SourceModule module;
+ module.path.push_back(ConstString(name));
+
+ DWARFDIE parent_die = module_die;
+ while ((parent_die = parent_die.GetParent())) {
+ if (parent_die.Tag() != DW_TAG_module)
+ break;
+ if (const char *name =
+ parent_die.GetAttributeValueAsString(DW_AT_name, nullptr))
+ module.path.push_back(ConstString(name));
+ }
+ std::reverse(module.path.begin(), module.path.end());
+ if (const char *include_path = module_die.GetAttributeValueAsString(
+ DW_AT_LLVM_include_path, nullptr)) {
+ FileSpec include_spec(include_path, dwarf_cu->GetPathStyle());
+ MakeAbsoluteAndRemap(include_spec, *dwarf_cu,
+ m_objfile_sp->GetModule());
+ module.search_path = ConstString(include_spec.GetPath());
+ }
+ if (const char *sysroot = dwarf_cu->DIE().GetAttributeValueAsString(
+ DW_AT_LLVM_sysroot, nullptr))
+ module.sysroot = ConstString(sysroot);
+ imported_modules.push_back(module);
+ }
+ }
+ return true;
+}
+
+bool SymbolFileDWARF::ParseLineTable(CompileUnit &comp_unit) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ if (comp_unit.GetLineTable() != nullptr)
+ return true;
+
+ DWARFUnit *dwarf_cu = GetDWARFCompileUnit(&comp_unit);
+ if (!dwarf_cu)
+ return false;
+
+ dw_offset_t offset = dwarf_cu->GetLineTableOffset();
+ if (offset == DW_INVALID_OFFSET)
+ return false;
+
+ ElapsedTime elapsed(m_parse_time);
+ llvm::DWARFDebugLine line;
+ const llvm::DWARFDebugLine::LineTable *line_table =
+ ParseLLVMLineTable(m_context, line, offset, dwarf_cu->GetOffset());
+
+ if (!line_table)
+ return false;
+
+ // FIXME: Rather than parsing the whole line table and then copying it over
+ // into LLDB, we should explore using a callback to populate the line table
+ // while we parse to reduce memory usage.
+ std::vector<std::unique_ptr<LineSequence>> sequences;
+ // The Sequences view contains only valid line sequences. Don't iterate over
+ // the Rows directly.
+ for (const llvm::DWARFDebugLine::Sequence &seq : line_table->Sequences) {
+ // Ignore line sequences that do not start after the first code address.
+ // All addresses generated in a sequence are incremental so we only need
+ // to check the first one of the sequence. Check the comment at the
+ // m_first_code_address declaration for more details on this.
+ if (seq.LowPC < m_first_code_address)
+ continue;
+ std::unique_ptr<LineSequence> sequence =
+ LineTable::CreateLineSequenceContainer();
+ for (unsigned idx = seq.FirstRowIndex; idx < seq.LastRowIndex; ++idx) {
+ const llvm::DWARFDebugLine::Row &row = line_table->Rows[idx];
+ LineTable::AppendLineEntryToSequence(
+ sequence.get(), row.Address.Address, row.Line, row.Column, row.File,
+ row.IsStmt, row.BasicBlock, row.PrologueEnd, row.EpilogueBegin,
+ row.EndSequence);
+ }
+ sequences.push_back(std::move(sequence));
+ }
+
+ std::unique_ptr<LineTable> line_table_up =
+ std::make_unique<LineTable>(&comp_unit, std::move(sequences));
+
+ if (SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile()) {
+ // We have an object file that has a line table with addresses that are not
+ // linked. We need to link the line table and convert the addresses that
+ // are relative to the .o file into addresses for the main executable.
+ comp_unit.SetLineTable(
+ debug_map_symfile->LinkOSOLineTable(this, line_table_up.get()));
+ } else {
+ comp_unit.SetLineTable(line_table_up.release());
+ }
+
+ return true;
+}
+
+lldb_private::DebugMacrosSP
+SymbolFileDWARF::ParseDebugMacros(lldb::offset_t *offset) {
+ auto iter = m_debug_macros_map.find(*offset);
+ if (iter != m_debug_macros_map.end())
+ return iter->second;
+
+ ElapsedTime elapsed(m_parse_time);
+ const DWARFDataExtractor &debug_macro_data = m_context.getOrLoadMacroData();
+ if (debug_macro_data.GetByteSize() == 0)
+ return DebugMacrosSP();
+
+ lldb_private::DebugMacrosSP debug_macros_sp(new lldb_private::DebugMacros());
+ m_debug_macros_map[*offset] = debug_macros_sp;
+
+ const DWARFDebugMacroHeader &header =
+ DWARFDebugMacroHeader::ParseHeader(debug_macro_data, offset);
+ DWARFDebugMacroEntry::ReadMacroEntries(
+ debug_macro_data, m_context.getOrLoadStrData(), header.OffsetIs64Bit(),
+ offset, this, debug_macros_sp);
+
+ return debug_macros_sp;
+}
+
+bool SymbolFileDWARF::ParseDebugMacros(CompileUnit &comp_unit) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+
+ DWARFUnit *dwarf_cu = GetDWARFCompileUnit(&comp_unit);
+ if (dwarf_cu == nullptr)
+ return false;
+
+ const DWARFBaseDIE dwarf_cu_die = dwarf_cu->GetUnitDIEOnly();
+ if (!dwarf_cu_die)
+ return false;
+
+ lldb::offset_t sect_offset =
+ dwarf_cu_die.GetAttributeValueAsUnsigned(DW_AT_macros, DW_INVALID_OFFSET);
+ if (sect_offset == DW_INVALID_OFFSET)
+ sect_offset = dwarf_cu_die.GetAttributeValueAsUnsigned(DW_AT_GNU_macros,
+ DW_INVALID_OFFSET);
+ if (sect_offset == DW_INVALID_OFFSET)
+ return false;
+
+ comp_unit.SetDebugMacros(ParseDebugMacros(&sect_offset));
+
+ return true;
+}
+
+size_t SymbolFileDWARF::ParseBlocksRecursive(
+ lldb_private::CompileUnit &comp_unit, Block *parent_block,
+ const DWARFDIE &orig_die, addr_t subprogram_low_pc, uint32_t depth) {
+ size_t blocks_added = 0;
+ DWARFDIE die = orig_die;
+ while (die) {
+ dw_tag_t tag = die.Tag();
+
+ switch (tag) {
+ case DW_TAG_inlined_subroutine:
+ case DW_TAG_subprogram:
+ case DW_TAG_lexical_block: {
+ Block *block = nullptr;
+ if (tag == DW_TAG_subprogram) {
+ // Skip any DW_TAG_subprogram DIEs that are inside of a normal or
+ // inlined functions. These will be parsed on their own as separate
+ // entities.
+
+ if (depth > 0)
+ break;
+
+ block = parent_block;
+ } else {
+ BlockSP block_sp(new Block(die.GetID()));
+ parent_block->AddChild(block_sp);
+ block = block_sp.get();
+ }
+ DWARFRangeList ranges;
+ const char *name = nullptr;
+ const char *mangled_name = nullptr;
+
+ std::optional<int> decl_file;
+ std::optional<int> decl_line;
+ std::optional<int> decl_column;
+ std::optional<int> call_file;
+ std::optional<int> call_line;
+ std::optional<int> call_column;
+ if (die.GetDIENamesAndRanges(name, mangled_name, ranges, decl_file,
+ decl_line, decl_column, call_file, call_line,
+ call_column, nullptr)) {
+ if (tag == DW_TAG_subprogram) {
+ assert(subprogram_low_pc == LLDB_INVALID_ADDRESS);
+ subprogram_low_pc = ranges.GetMinRangeBase(0);
+ } else if (tag == DW_TAG_inlined_subroutine) {
+ // We get called here for inlined subroutines in two ways. The first
+ // time is when we are making the Function object for this inlined
+ // concrete instance. Since we're creating a top level block at
+ // here, the subprogram_low_pc will be LLDB_INVALID_ADDRESS. So we
+ // need to adjust the containing address. The second time is when we
+ // are parsing the blocks inside the function that contains the
+ // inlined concrete instance. Since these will be blocks inside the
+ // containing "real" function the offset will be for that function.
+ if (subprogram_low_pc == LLDB_INVALID_ADDRESS) {
+ subprogram_low_pc = ranges.GetMinRangeBase(0);
+ }
+ }
+
+ const size_t num_ranges = ranges.GetSize();
+ for (size_t i = 0; i < num_ranges; ++i) {
+ const DWARFRangeList::Entry &range = ranges.GetEntryRef(i);
+ const addr_t range_base = range.GetRangeBase();
+ if (range_base >= subprogram_low_pc)
+ block->AddRange(Block::Range(range_base - subprogram_low_pc,
+ range.GetByteSize()));
+ else {
+ GetObjectFile()->GetModule()->ReportError(
+ "{0:x8}: adding range [{1:x16}-{2:x16}) which has a base "
+ "that is less than the function's low PC {3:x16}. Please file "
+ "a bug and attach the file at the "
+ "start of this error message",
+ block->GetID(), range_base, range.GetRangeEnd(),
+ subprogram_low_pc);
+ }
+ }
+ block->FinalizeRanges();
+
+ if (tag != DW_TAG_subprogram &&
+ (name != nullptr || mangled_name != nullptr)) {
+ std::unique_ptr<Declaration> decl_up;
+ if (decl_file || decl_line || decl_column)
+ decl_up = std::make_unique<Declaration>(
+ comp_unit.GetSupportFiles().GetFileSpecAtIndex(
+ decl_file ? *decl_file : 0),
+ decl_line ? *decl_line : 0, decl_column ? *decl_column : 0);
+
+ std::unique_ptr<Declaration> call_up;
+ if (call_file || call_line || call_column)
+ call_up = std::make_unique<Declaration>(
+ comp_unit.GetSupportFiles().GetFileSpecAtIndex(
+ call_file ? *call_file : 0),
+ call_line ? *call_line : 0, call_column ? *call_column : 0);
+
+ block->SetInlinedFunctionInfo(name, mangled_name, decl_up.get(),
+ call_up.get());
+ }
+
+ ++blocks_added;
+
+ if (die.HasChildren()) {
+ blocks_added +=
+ ParseBlocksRecursive(comp_unit, block, die.GetFirstChild(),
+ subprogram_low_pc, depth + 1);
+ }
+ }
+ } break;
+ default:
+ break;
+ }
+
+ // Only parse siblings of the block if we are not at depth zero. A depth of
+ // zero indicates we are currently parsing the top level DW_TAG_subprogram
+ // DIE
+
+ if (depth == 0)
+ die.Clear();
+ else
+ die = die.GetSibling();
+ }
+ return blocks_added;
+}
+
+bool SymbolFileDWARF::ClassOrStructIsVirtual(const DWARFDIE &parent_die) {
+ if (parent_die) {
+ for (DWARFDIE die : parent_die.children()) {
+ dw_tag_t tag = die.Tag();
+ bool check_virtuality = false;
+ switch (tag) {
+ case DW_TAG_inheritance:
+ case DW_TAG_subprogram:
+ check_virtuality = true;
+ break;
+ default:
+ break;
+ }
+ if (check_virtuality) {
+ if (die.GetAttributeValueAsUnsigned(DW_AT_virtuality, 0) != 0)
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void SymbolFileDWARF::ParseDeclsForContext(CompilerDeclContext decl_ctx) {
+ auto *type_system = decl_ctx.GetTypeSystem();
+ if (type_system != nullptr)
+ type_system->GetDWARFParser()->EnsureAllDIEsInDeclContextHaveBeenParsed(
+ decl_ctx);
+}
+
+DWARFDIE
+SymbolFileDWARF::GetDIE(lldb::user_id_t uid) { return GetDIE(DIERef(uid)); }
+
+CompilerDecl SymbolFileDWARF::GetDeclForUID(lldb::user_id_t type_uid) {
+ // This method can be called without going through the symbol vendor so we
+ // need to lock the module.
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ // Anytime we have a lldb::user_id_t, we must get the DIE by calling
+ // SymbolFileDWARF::GetDIE(). See comments inside the
+ // SymbolFileDWARF::GetDIE() for details.
+ if (DWARFDIE die = GetDIE(type_uid))
+ return GetDecl(die);
+ return CompilerDecl();
+}
+
+CompilerDeclContext
+SymbolFileDWARF::GetDeclContextForUID(lldb::user_id_t type_uid) {
+ // This method can be called without going through the symbol vendor so we
+ // need to lock the module.
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ // Anytime we have a lldb::user_id_t, we must get the DIE by calling
+ // SymbolFileDWARF::GetDIE(). See comments inside the
+ // SymbolFileDWARF::GetDIE() for details.
+ if (DWARFDIE die = GetDIE(type_uid))
+ return GetDeclContext(die);
+ return CompilerDeclContext();
+}
+
+CompilerDeclContext
+SymbolFileDWARF::GetDeclContextContainingUID(lldb::user_id_t type_uid) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ // Anytime we have a lldb::user_id_t, we must get the DIE by calling
+ // SymbolFileDWARF::GetDIE(). See comments inside the
+ // SymbolFileDWARF::GetDIE() for details.
+ if (DWARFDIE die = GetDIE(type_uid))
+ return GetContainingDeclContext(die);
+ return CompilerDeclContext();
+}
+
+std::vector<CompilerContext>
+SymbolFileDWARF::GetCompilerContextForUID(lldb::user_id_t type_uid) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ // Anytime we have a lldb::user_id_t, we must get the DIE by calling
+ // SymbolFileDWARF::GetDIE(). See comments inside the
+ // SymbolFileDWARF::GetDIE() for details.
+ if (DWARFDIE die = GetDIE(type_uid))
+ return die.GetDeclContext();
+ return {};
+}
+
+Type *SymbolFileDWARF::ResolveTypeUID(lldb::user_id_t type_uid) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ // Anytime we have a lldb::user_id_t, we must get the DIE by calling
+ // SymbolFileDWARF::GetDIE(). See comments inside the
+ // SymbolFileDWARF::GetDIE() for details.
+ if (DWARFDIE type_die = GetDIE(type_uid))
+ return type_die.ResolveType();
+ else
+ return nullptr;
+}
+
+std::optional<SymbolFile::ArrayInfo> SymbolFileDWARF::GetDynamicArrayInfoForUID(
+ lldb::user_id_t type_uid, const lldb_private::ExecutionContext *exe_ctx) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ if (DWARFDIE type_die = GetDIE(type_uid))
+ return DWARFASTParser::ParseChildArrayInfo(type_die, exe_ctx);
+ else
+ return std::nullopt;
+}
+
+Type *SymbolFileDWARF::ResolveTypeUID(const DIERef &die_ref) {
+ return ResolveType(GetDIE(die_ref), true);
+}
+
+Type *SymbolFileDWARF::ResolveTypeUID(const DWARFDIE &die,
+ bool assert_not_being_parsed) {
+ if (die) {
+ Log *log = GetLog(DWARFLog::DebugInfo);
+ if (log)
+ GetObjectFile()->GetModule()->LogMessage(
+ log,
+ "SymbolFileDWARF::ResolveTypeUID (die = {0:x16}) {1} ({2}) '{3}'",
+ die.GetOffset(), DW_TAG_value_to_name(die.Tag()), die.Tag(),
+ die.GetName());
+
+ // We might be coming in in the middle of a type tree (a class within a
+ // class, an enum within a class), so parse any needed parent DIEs before
+ // we get to this one...
+ DWARFDIE decl_ctx_die = GetDeclContextDIEContainingDIE(die);
+ if (decl_ctx_die) {
+ if (log) {
+ switch (decl_ctx_die.Tag()) {
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_class_type: {
+ // Get the type, which could be a forward declaration
+ if (log)
+ GetObjectFile()->GetModule()->LogMessage(
+ log,
+ "SymbolFileDWARF::ResolveTypeUID (die = {0:x16}) {1} ({2}) "
+ "'{3}' resolve parent forward type for {4:x16})",
+ die.GetOffset(), DW_TAG_value_to_name(die.Tag()), die.Tag(),
+ die.GetName(), decl_ctx_die.GetOffset());
+ } break;
+
+ default:
+ break;
+ }
+ }
+ }
+ return ResolveType(die);
+ }
+ return nullptr;
+}
+
+// This function is used when SymbolFileDWARFDebugMap owns a bunch of
+// SymbolFileDWARF objects to detect if this DWARF file is the one that can
+// resolve a compiler_type.
+bool SymbolFileDWARF::HasForwardDeclForCompilerType(
+ const CompilerType &compiler_type) {
+ CompilerType compiler_type_no_qualifiers =
+ ClangUtil::RemoveFastQualifiers(compiler_type);
+ if (GetForwardDeclCompilerTypeToDIE().count(
+ compiler_type_no_qualifiers.GetOpaqueQualType())) {
+ return true;
+ }
+ auto type_system = compiler_type.GetTypeSystem();
+ auto clang_type_system = type_system.dyn_cast_or_null<TypeSystemClang>();
+ if (!clang_type_system)
+ return false;
+ DWARFASTParserClang *ast_parser =
+ static_cast<DWARFASTParserClang *>(clang_type_system->GetDWARFParser());
+ return ast_parser->GetClangASTImporter().CanImport(compiler_type);
+}
+
+bool SymbolFileDWARF::CompleteType(CompilerType &compiler_type) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ auto clang_type_system =
+ compiler_type.GetTypeSystem().dyn_cast_or_null<TypeSystemClang>();
+ if (clang_type_system) {
+ DWARFASTParserClang *ast_parser =
+ static_cast<DWARFASTParserClang *>(clang_type_system->GetDWARFParser());
+ if (ast_parser &&
+ ast_parser->GetClangASTImporter().CanImport(compiler_type))
+ return ast_parser->GetClangASTImporter().CompleteType(compiler_type);
+ }
+
+ // We have a struct/union/class/enum that needs to be fully resolved.
+ CompilerType compiler_type_no_qualifiers =
+ ClangUtil::RemoveFastQualifiers(compiler_type);
+ auto die_it = GetForwardDeclCompilerTypeToDIE().find(
+ compiler_type_no_qualifiers.GetOpaqueQualType());
+ if (die_it == GetForwardDeclCompilerTypeToDIE().end()) {
+ // We have already resolved this type...
+ return true;
+ }
+
+ DWARFDIE decl_die = GetDIE(die_it->getSecond());
+ // Once we start resolving this type, remove it from the forward
+ // declaration map in case anyone's child members or other types require this
+ // type to get resolved.
+ GetForwardDeclCompilerTypeToDIE().erase(die_it);
+ DWARFDIE def_die = FindDefinitionDIE(decl_die);
+ if (!def_die) {
+ SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile();
+ if (debug_map_symfile) {
+ // We weren't able to find a full declaration in this DWARF, see
+ // if we have a declaration anywhere else...
+ def_die = debug_map_symfile->FindDefinitionDIE(decl_die);
+ }
+ }
+ if (!def_die) {
+ // If we don't have definition DIE, CompleteTypeFromDWARF will forcefully
+ // complete this type.
+ def_die = decl_die;
+ }
+
+ DWARFASTParser *dwarf_ast = GetDWARFParser(*def_die.GetCU());
+ if (!dwarf_ast)
+ return false;
+ Type *type = GetDIEToType().lookup(decl_die.GetDIE());
+ if (decl_die != def_die) {
+ GetDIEToType()[def_die.GetDIE()] = type;
+ DWARFASTParserClang *ast_parser =
+ static_cast<DWARFASTParserClang *>(dwarf_ast);
+ ast_parser->MapDeclDIEToDefDIE(decl_die, def_die);
+ }
+
+ Log *log = GetLog(DWARFLog::DebugInfo | DWARFLog::TypeCompletion);
+ if (log)
+ GetObjectFile()->GetModule()->LogMessageVerboseBacktrace(
+ log, "{0:x8}: {1} ({2}) '{3}' resolving forward declaration...",
+ def_die.GetID(), DW_TAG_value_to_name(def_die.Tag()), def_die.Tag(),
+ type->GetName().AsCString());
+ assert(compiler_type);
+ return dwarf_ast->CompleteTypeFromDWARF(def_die, type, compiler_type);
+}
+
+Type *SymbolFileDWARF::ResolveType(const DWARFDIE &die,
+ bool assert_not_being_parsed,
+ bool resolve_function_context) {
+ if (die) {
+ Type *type = GetTypeForDIE(die, resolve_function_context).get();
+
+ if (assert_not_being_parsed) {
+ if (type != DIE_IS_BEING_PARSED)
+ return type;
+
+ GetObjectFile()->GetModule()->ReportError(
+ "Parsing a die that is being parsed die: {0:x16}: {1} ({2}) {3}",
+ die.GetOffset(), DW_TAG_value_to_name(die.Tag()), die.Tag(),
+ die.GetName());
+
+ } else
+ return type;
+ }
+ return nullptr;
+}
+
+CompileUnit *
+SymbolFileDWARF::GetCompUnitForDWARFCompUnit(DWARFCompileUnit &dwarf_cu) {
+
+ if (dwarf_cu.IsDWOUnit()) {
+ DWARFCompileUnit *non_dwo_cu = dwarf_cu.GetSkeletonUnit();
+ assert(non_dwo_cu);
+ return non_dwo_cu->GetSymbolFileDWARF().GetCompUnitForDWARFCompUnit(
+ *non_dwo_cu);
+ }
+ // Check if the symbol vendor already knows about this compile unit?
+ CompileUnit *lldb_cu = dwarf_cu.GetLLDBCompUnit();
+ if (lldb_cu)
+ return lldb_cu;
+ // The symbol vendor doesn't know about this compile unit, we need to parse
+ // and add it to the symbol vendor object.
+ return ParseCompileUnit(dwarf_cu).get();
+}
+
+void SymbolFileDWARF::GetObjCMethods(
+ ConstString class_name, llvm::function_ref<bool(DWARFDIE die)> callback) {
+ m_index->GetObjCMethods(class_name, callback);
+}
+
+bool SymbolFileDWARF::GetFunction(const DWARFDIE &die, SymbolContext &sc) {
+ sc.Clear(false);
+
+ if (die && llvm::isa<DWARFCompileUnit>(die.GetCU())) {
+ // Check if the symbol vendor already knows about this compile unit?
+ sc.comp_unit =
+ GetCompUnitForDWARFCompUnit(llvm::cast<DWARFCompileUnit>(*die.GetCU()));
+
+ sc.function = sc.comp_unit->FindFunctionByUID(die.GetID()).get();
+ if (sc.function == nullptr)
+ sc.function = ParseFunction(*sc.comp_unit, die);
+
+ if (sc.function) {
+ sc.module_sp = sc.function->CalculateSymbolContextModule();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+lldb::ModuleSP SymbolFileDWARF::GetExternalModule(ConstString name) {
+ UpdateExternalModuleListIfNeeded();
+ const auto &pos = m_external_type_modules.find(name);
+ if (pos == m_external_type_modules.end())
+ return lldb::ModuleSP();
+ return pos->second;
+}
+
+SymbolFileDWARF *SymbolFileDWARF::GetDIERefSymbolFile(const DIERef &die_ref) {
+ // Anytime we get a "lldb::user_id_t" from an lldb_private::SymbolFile API we
+ // must make sure we use the correct DWARF file when resolving things. On
+ // MacOSX, when using SymbolFileDWARFDebugMap, we will use multiple
+ // SymbolFileDWARF classes, one for each .o file. We can often end up with
+ // references to other DWARF objects and we must be ready to receive a
+ // "lldb::user_id_t" that specifies a DIE from another SymbolFileDWARF
+ // instance.
+
+ std::optional<uint32_t> file_index = die_ref.file_index();
+
+ // If the file index matches, then we have the right SymbolFileDWARF already.
+ // This will work for both .dwo file and DWARF in .o files for mac. Also if
+ // both the file indexes are invalid, then we have a match.
+ if (GetFileIndex() == file_index)
+ return this;
+
+ if (file_index) {
+ // We have a SymbolFileDWARFDebugMap, so let it find the right file
+ if (SymbolFileDWARFDebugMap *debug_map = GetDebugMapSymfile())
+ return debug_map->GetSymbolFileByOSOIndex(*file_index);
+
+ // Handle the .dwp file case correctly
+ if (*file_index == DIERef::k_file_index_mask)
+ return GetDwpSymbolFile().get(); // DWP case
+
+ // Handle the .dwo file case correctly
+ return DebugInfo().GetUnitAtIndex(*die_ref.file_index())
+ ->GetDwoSymbolFile(); // DWO case
+ }
+ return this;
+}
+
+DWARFDIE
+SymbolFileDWARF::GetDIE(const DIERef &die_ref) {
+ if (die_ref.die_offset() == DW_INVALID_OFFSET)
+ return DWARFDIE();
+
+ // This method can be called without going through the symbol vendor so we
+ // need to lock the module.
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ SymbolFileDWARF *symbol_file = GetDIERefSymbolFile(die_ref);
+ if (symbol_file)
+ return symbol_file->DebugInfo().GetDIE(die_ref.section(),
+ die_ref.die_offset());
+ return DWARFDIE();
+}
+
+/// Return the DW_AT_(GNU_)dwo_id.
+static std::optional<uint64_t> GetDWOId(DWARFCompileUnit &dwarf_cu,
+ const DWARFDebugInfoEntry &cu_die) {
+ std::optional<uint64_t> dwo_id =
+ cu_die.GetAttributeValueAsOptionalUnsigned(&dwarf_cu, DW_AT_GNU_dwo_id);
+ if (dwo_id)
+ return dwo_id;
+ return cu_die.GetAttributeValueAsOptionalUnsigned(&dwarf_cu, DW_AT_dwo_id);
+}
+
+std::optional<uint64_t> SymbolFileDWARF::GetDWOId() {
+ if (GetNumCompileUnits() == 1) {
+ if (auto comp_unit = GetCompileUnitAtIndex(0))
+ if (DWARFCompileUnit *cu = GetDWARFCompileUnit(comp_unit.get()))
+ if (DWARFDebugInfoEntry *cu_die = cu->DIE().GetDIE())
+ return ::GetDWOId(*cu, *cu_die);
+ }
+ return {};
+}
+
+DWARFUnit *SymbolFileDWARF::GetSkeletonUnit(DWARFUnit *dwo_unit) {
+ return DebugInfo().GetSkeletonUnit(dwo_unit);
+}
+
+std::shared_ptr<SymbolFileDWARFDwo>
+SymbolFileDWARF::GetDwoSymbolFileForCompileUnit(
+ DWARFUnit &unit, const DWARFDebugInfoEntry &cu_die) {
+ // If this is a Darwin-style debug map (non-.dSYM) symbol file,
+ // never attempt to load ELF-style DWO files since the -gmodules
+ // support uses the same DWO mechanism to specify full debug info
+ // files for modules. This is handled in
+ // UpdateExternalModuleListIfNeeded().
+ if (GetDebugMapSymfile())
+ return nullptr;
+
+ DWARFCompileUnit *dwarf_cu = llvm::dyn_cast<DWARFCompileUnit>(&unit);
+ // Only compile units can be split into two parts and we should only
+ // look for a DWO file if there is a valid DWO ID.
+ if (!dwarf_cu || !dwarf_cu->GetDWOId().has_value())
+ return nullptr;
+
+ const char *dwo_name = GetDWOName(*dwarf_cu, cu_die);
+ if (!dwo_name) {
+ unit.SetDwoError(Status::createWithFormat(
+ "missing DWO name in skeleton DIE {0:x16}", cu_die.GetOffset()));
+ return nullptr;
+ }
+
+ if (std::shared_ptr<SymbolFileDWARFDwo> dwp_sp = GetDwpSymbolFile())
+ return dwp_sp;
+
+ FileSpec dwo_file(dwo_name);
+ FileSystem::Instance().Resolve(dwo_file);
+ bool found = false;
+
+ const FileSpecList &debug_file_search_paths =
+ Target::GetDefaultDebugFileSearchPaths();
+ size_t num_search_paths = debug_file_search_paths.GetSize();
+
+ // It's relative, e.g. "foo.dwo", but we just to happen to be right next to
+ // it. Or it's absolute.
+ found = FileSystem::Instance().Exists(dwo_file);
+
+ const char *comp_dir =
+ cu_die.GetAttributeValueAsString(dwarf_cu, DW_AT_comp_dir, nullptr);
+ if (!found) {
+ // It could be a relative path that also uses DW_AT_COMP_DIR.
+ if (comp_dir) {
+ dwo_file.SetFile(comp_dir, FileSpec::Style::native);
+ if (!dwo_file.IsRelative()) {
+ FileSystem::Instance().Resolve(dwo_file);
+ dwo_file.AppendPathComponent(dwo_name);
+ found = FileSystem::Instance().Exists(dwo_file);
+ } else {
+ FileSpecList dwo_paths;
+
+ // if DW_AT_comp_dir is relative, it should be relative to the location
+ // of the executable, not to the location from which the debugger was
+ // launched.
+ FileSpec relative_to_binary = dwo_file;
+ relative_to_binary.PrependPathComponent(
+ m_objfile_sp->GetFileSpec().GetDirectory().GetStringRef());
+ FileSystem::Instance().Resolve(relative_to_binary);
+ relative_to_binary.AppendPathComponent(dwo_name);
+ dwo_paths.Append(relative_to_binary);
+
+ // Or it's relative to one of the user specified debug directories.
+ for (size_t idx = 0; idx < num_search_paths; ++idx) {
+ FileSpec dirspec = debug_file_search_paths.GetFileSpecAtIndex(idx);
+ dirspec.AppendPathComponent(comp_dir);
+ FileSystem::Instance().Resolve(dirspec);
+ if (!FileSystem::Instance().IsDirectory(dirspec))
+ continue;
+
+ dirspec.AppendPathComponent(dwo_name);
+ dwo_paths.Append(dirspec);
+ }
+
+ size_t num_possible = dwo_paths.GetSize();
+ for (size_t idx = 0; idx < num_possible && !found; ++idx) {
+ FileSpec dwo_spec = dwo_paths.GetFileSpecAtIndex(idx);
+ if (FileSystem::Instance().Exists(dwo_spec)) {
+ dwo_file = dwo_spec;
+ found = true;
+ }
+ }
+ }
+ } else {
+ Log *log = GetLog(LLDBLog::Symbols);
+ LLDB_LOGF(log,
+ "unable to locate relative .dwo debug file \"%s\" for "
+ "skeleton DIE 0x%016" PRIx64 " without valid DW_AT_comp_dir "
+ "attribute",
+ dwo_name, cu_die.GetOffset());
+ }
+ }
+
+ if (!found) {
+ // Try adding the DW_AT_dwo_name ( e.g. "c/d/main-main.dwo"), and just the
+ // filename ("main-main.dwo") to binary dir and search paths.
+ FileSpecList dwo_paths;
+ FileSpec dwo_name_spec(dwo_name);
+ llvm::StringRef filename_only = dwo_name_spec.GetFilename();
+
+ FileSpec binary_directory(
+ m_objfile_sp->GetFileSpec().GetDirectory().GetStringRef());
+ FileSystem::Instance().Resolve(binary_directory);
+
+ if (dwo_name_spec.IsRelative()) {
+ FileSpec dwo_name_binary_directory(binary_directory);
+ dwo_name_binary_directory.AppendPathComponent(dwo_name);
+ dwo_paths.Append(dwo_name_binary_directory);
+ }
+
+ FileSpec filename_binary_directory(binary_directory);
+ filename_binary_directory.AppendPathComponent(filename_only);
+ dwo_paths.Append(filename_binary_directory);
+
+ for (size_t idx = 0; idx < num_search_paths; ++idx) {
+ FileSpec dirspec = debug_file_search_paths.GetFileSpecAtIndex(idx);
+ FileSystem::Instance().Resolve(dirspec);
+ if (!FileSystem::Instance().IsDirectory(dirspec))
+ continue;
+
+ FileSpec dwo_name_dirspec(dirspec);
+ dwo_name_dirspec.AppendPathComponent(dwo_name);
+ dwo_paths.Append(dwo_name_dirspec);
+
+ FileSpec filename_dirspec(dirspec);
+ filename_dirspec.AppendPathComponent(filename_only);
+ dwo_paths.Append(filename_dirspec);
+ }
+
+ size_t num_possible = dwo_paths.GetSize();
+ for (size_t idx = 0; idx < num_possible && !found; ++idx) {
+ FileSpec dwo_spec = dwo_paths.GetFileSpecAtIndex(idx);
+ if (FileSystem::Instance().Exists(dwo_spec)) {
+ dwo_file = dwo_spec;
+ found = true;
+ }
+ }
+ }
+
+ if (!found) {
+ FileSpec error_dwo_path(dwo_name);
+ FileSystem::Instance().Resolve(error_dwo_path);
+ if (error_dwo_path.IsRelative() && comp_dir != nullptr) {
+ error_dwo_path.PrependPathComponent(comp_dir);
+ FileSystem::Instance().Resolve(error_dwo_path);
+ }
+ unit.SetDwoError(Status::createWithFormat(
+ "unable to locate .dwo debug file \"{0}\" for skeleton DIE "
+ "{1:x16}",
+ error_dwo_path.GetPath().c_str(), cu_die.GetOffset()));
+
+ if (m_dwo_warning_issued.test_and_set(std::memory_order_relaxed) == false) {
+ GetObjectFile()->GetModule()->ReportWarning(
+ "unable to locate separate debug file (dwo, dwp). Debugging will be "
+ "degraded.");
+ }
+ return nullptr;
+ }
+
+ const lldb::offset_t file_offset = 0;
+ DataBufferSP dwo_file_data_sp;
+ lldb::offset_t dwo_file_data_offset = 0;
+ ObjectFileSP dwo_obj_file = ObjectFile::FindPlugin(
+ GetObjectFile()->GetModule(), &dwo_file, file_offset,
+ FileSystem::Instance().GetByteSize(dwo_file), dwo_file_data_sp,
+ dwo_file_data_offset);
+ if (dwo_obj_file == nullptr) {
+ unit.SetDwoError(Status::createWithFormat(
+ "unable to load object file for .dwo debug file \"{0}\" for "
+ "unit DIE {1:x16}",
+ dwo_name, cu_die.GetOffset()));
+ return nullptr;
+ }
+
+ return std::make_shared<SymbolFileDWARFDwo>(*this, dwo_obj_file,
+ dwarf_cu->GetID());
+}
+
+void SymbolFileDWARF::UpdateExternalModuleListIfNeeded() {
+ if (m_fetched_external_modules)
+ return;
+ m_fetched_external_modules = true;
+ DWARFDebugInfo &debug_info = DebugInfo();
+
+ // Follow DWO skeleton unit breadcrumbs.
+ const uint32_t num_compile_units = GetNumCompileUnits();
+ for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) {
+ auto *dwarf_cu =
+ llvm::dyn_cast<DWARFCompileUnit>(debug_info.GetUnitAtIndex(cu_idx));
+ if (!dwarf_cu)
+ continue;
+
+ const DWARFBaseDIE die = dwarf_cu->GetUnitDIEOnly();
+ if (!die || die.HasChildren() || !die.GetDIE())
+ continue;
+
+ const char *name = die.GetAttributeValueAsString(DW_AT_name, nullptr);
+ if (!name)
+ continue;
+
+ ConstString const_name(name);
+ ModuleSP &module_sp = m_external_type_modules[const_name];
+ if (module_sp)
+ continue;
+
+ const char *dwo_path = GetDWOName(*dwarf_cu, *die.GetDIE());
+ if (!dwo_path)
+ continue;
+
+ ModuleSpec dwo_module_spec;
+ dwo_module_spec.GetFileSpec().SetFile(dwo_path, FileSpec::Style::native);
+ if (dwo_module_spec.GetFileSpec().IsRelative()) {
+ const char *comp_dir =
+ die.GetAttributeValueAsString(DW_AT_comp_dir, nullptr);
+ if (comp_dir) {
+ dwo_module_spec.GetFileSpec().SetFile(comp_dir,
+ FileSpec::Style::native);
+ FileSystem::Instance().Resolve(dwo_module_spec.GetFileSpec());
+ dwo_module_spec.GetFileSpec().AppendPathComponent(dwo_path);
+ }
+ }
+ dwo_module_spec.GetArchitecture() =
+ m_objfile_sp->GetModule()->GetArchitecture();
+
+ // When LLDB loads "external" modules it looks at the presence of
+ // DW_AT_dwo_name. However, when the already created module
+ // (corresponding to .dwo itself) is being processed, it will see
+ // the presence of DW_AT_dwo_name (which contains the name of dwo
+ // file) and will try to call ModuleList::GetSharedModule
+ // again. In some cases (i.e., for empty files) Clang 4.0
+ // generates a *.dwo file which has DW_AT_dwo_name, but no
+ // DW_AT_comp_dir. In this case the method
+ // ModuleList::GetSharedModule will fail and the warning will be
+ // printed. However, as one can notice in this case we don't
+ // actually need to try to load the already loaded module
+ // (corresponding to .dwo) so we simply skip it.
+ if (m_objfile_sp->GetFileSpec().GetFileNameExtension() == ".dwo" &&
+ llvm::StringRef(m_objfile_sp->GetFileSpec().GetPath())
+ .ends_with(dwo_module_spec.GetFileSpec().GetPath())) {
+ continue;
+ }
+
+ Status error = ModuleList::GetSharedModule(dwo_module_spec, module_sp,
+ nullptr, nullptr, nullptr);
+ if (!module_sp) {
+ GetObjectFile()->GetModule()->ReportWarning(
+ "{0:x16}: unable to locate module needed for external types: "
+ "{1}\nerror: {2}\nDebugging will be degraded due to missing "
+ "types. Rebuilding the project will regenerate the needed "
+ "module files.",
+ die.GetOffset(), dwo_module_spec.GetFileSpec().GetPath().c_str(),
+ error.AsCString("unknown error"));
+ continue;
+ }
+
+ // Verify the DWO hash.
+ // FIXME: Technically "0" is a valid hash.
+ std::optional<uint64_t> dwo_id = ::GetDWOId(*dwarf_cu, *die.GetDIE());
+ if (!dwo_id)
+ continue;
+
+ auto *dwo_symfile =
+ llvm::dyn_cast_or_null<SymbolFileDWARF>(module_sp->GetSymbolFile());
+ if (!dwo_symfile)
+ continue;
+ std::optional<uint64_t> dwo_dwo_id = dwo_symfile->GetDWOId();
+ if (!dwo_dwo_id)
+ continue;
+
+ if (dwo_id != dwo_dwo_id) {
+ GetObjectFile()->GetModule()->ReportWarning(
+ "{0:x16}: Module {1} is out-of-date (hash mismatch). Type "
+ "information "
+ "from this module may be incomplete or inconsistent with the rest of "
+ "the program. Rebuilding the project will regenerate the needed "
+ "module files.",
+ die.GetOffset(), dwo_module_spec.GetFileSpec().GetPath().c_str());
+ }
+ }
+}
+
+SymbolFileDWARF::GlobalVariableMap &SymbolFileDWARF::GetGlobalAranges() {
+ if (!m_global_aranges_up) {
+ m_global_aranges_up = std::make_unique<GlobalVariableMap>();
+
+ ModuleSP module_sp = GetObjectFile()->GetModule();
+ if (module_sp) {
+ const size_t num_cus = module_sp->GetNumCompileUnits();
+ for (size_t i = 0; i < num_cus; ++i) {
+ CompUnitSP cu_sp = module_sp->GetCompileUnitAtIndex(i);
+ if (cu_sp) {
+ VariableListSP globals_sp = cu_sp->GetVariableList(true);
+ if (globals_sp) {
+ const size_t num_globals = globals_sp->GetSize();
+ for (size_t g = 0; g < num_globals; ++g) {
+ VariableSP var_sp = globals_sp->GetVariableAtIndex(g);
+ if (var_sp && !var_sp->GetLocationIsConstantValueData()) {
+ const DWARFExpressionList &location =
+ var_sp->LocationExpressionList();
+ ExecutionContext exe_ctx;
+ llvm::Expected<Value> location_result = location.Evaluate(
+ &exe_ctx, nullptr, LLDB_INVALID_ADDRESS, nullptr, nullptr);
+ if (location_result) {
+ if (location_result->GetValueType() ==
+ Value::ValueType::FileAddress) {
+ lldb::addr_t file_addr =
+ location_result->GetScalar().ULongLong();
+ lldb::addr_t byte_size = 1;
+ if (var_sp->GetType())
+ byte_size =
+ var_sp->GetType()->GetByteSize(nullptr).value_or(0);
+ m_global_aranges_up->Append(GlobalVariableMap::Entry(
+ file_addr, byte_size, var_sp.get()));
+ }
+ } else {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Symbols),
+ location_result.takeError(),
+ "location expression failed to execute: {0}");
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ m_global_aranges_up->Sort();
+ }
+ return *m_global_aranges_up;
+}
+
+void SymbolFileDWARF::ResolveFunctionAndBlock(lldb::addr_t file_vm_addr,
+ bool lookup_block,
+ SymbolContext &sc) {
+ assert(sc.comp_unit);
+ DWARFCompileUnit &cu =
+ GetDWARFCompileUnit(sc.comp_unit)->GetNonSkeletonUnit();
+ DWARFDIE function_die = cu.LookupAddress(file_vm_addr);
+ DWARFDIE block_die;
+ if (function_die) {
+ sc.function = sc.comp_unit->FindFunctionByUID(function_die.GetID()).get();
+ if (sc.function == nullptr)
+ sc.function = ParseFunction(*sc.comp_unit, function_die);
+
+ if (sc.function && lookup_block)
+ block_die = function_die.LookupDeepestBlock(file_vm_addr);
+ }
+
+ if (!sc.function || !lookup_block)
+ return;
+
+ Block &block = sc.function->GetBlock(true);
+ if (block_die)
+ sc.block = block.FindBlockByID(block_die.GetID());
+ else
+ sc.block = block.FindBlockByID(function_die.GetID());
+}
+
+uint32_t SymbolFileDWARF::ResolveSymbolContext(const Address &so_addr,
+ SymbolContextItem resolve_scope,
+ SymbolContext &sc) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ LLDB_SCOPED_TIMERF("SymbolFileDWARF::"
+ "ResolveSymbolContext (so_addr = { "
+ "section = %p, offset = 0x%" PRIx64
+ " }, resolve_scope = 0x%8.8x)",
+ static_cast<void *>(so_addr.GetSection().get()),
+ so_addr.GetOffset(), resolve_scope);
+ uint32_t resolved = 0;
+ if (resolve_scope &
+ (eSymbolContextCompUnit | eSymbolContextFunction | eSymbolContextBlock |
+ eSymbolContextLineEntry | eSymbolContextVariable)) {
+ lldb::addr_t file_vm_addr = so_addr.GetFileAddress();
+
+ DWARFDebugInfo &debug_info = DebugInfo();
+ const DWARFDebugAranges &aranges = debug_info.GetCompileUnitAranges();
+ const dw_offset_t cu_offset = aranges.FindAddress(file_vm_addr);
+ if (cu_offset == DW_INVALID_OFFSET) {
+ // Global variables are not in the compile unit address ranges. The only
+ // way to currently find global variables is to iterate over the
+ // .debug_pubnames or the __apple_names table and find all items in there
+ // that point to DW_TAG_variable DIEs and then find the address that
+ // matches.
+ if (resolve_scope & eSymbolContextVariable) {
+ GlobalVariableMap &map = GetGlobalAranges();
+ const GlobalVariableMap::Entry *entry =
+ map.FindEntryThatContains(file_vm_addr);
+ if (entry && entry->data) {
+ Variable *variable = entry->data;
+ SymbolContextScope *scc = variable->GetSymbolContextScope();
+ if (scc) {
+ scc->CalculateSymbolContext(&sc);
+ sc.variable = variable;
+ }
+ return sc.GetResolvedMask();
+ }
+ }
+ } else {
+ uint32_t cu_idx = DW_INVALID_INDEX;
+ if (auto *dwarf_cu = llvm::dyn_cast_or_null<DWARFCompileUnit>(
+ debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, cu_offset,
+ &cu_idx))) {
+ sc.comp_unit = GetCompUnitForDWARFCompUnit(*dwarf_cu);
+ if (sc.comp_unit) {
+ resolved |= eSymbolContextCompUnit;
+
+ bool force_check_line_table = false;
+ if (resolve_scope & (eSymbolContextFunction | eSymbolContextBlock)) {
+ ResolveFunctionAndBlock(file_vm_addr,
+ resolve_scope & eSymbolContextBlock, sc);
+ if (sc.function)
+ resolved |= eSymbolContextFunction;
+ else {
+ // We might have had a compile unit that had discontiguous address
+ // ranges where the gaps are symbols that don't have any debug
+ // info. Discontiguous compile unit address ranges should only
+ // happen when there aren't other functions from other compile
+ // units in these gaps. This helps keep the size of the aranges
+ // down.
+ force_check_line_table = true;
+ }
+ if (sc.block)
+ resolved |= eSymbolContextBlock;
+ }
+
+ if ((resolve_scope & eSymbolContextLineEntry) ||
+ force_check_line_table) {
+ LineTable *line_table = sc.comp_unit->GetLineTable();
+ if (line_table != nullptr) {
+ // And address that makes it into this function should be in terms
+ // of this debug file if there is no debug map, or it will be an
+ // address in the .o file which needs to be fixed up to be in
+ // terms of the debug map executable. Either way, calling
+ // FixupAddress() will work for us.
+ Address exe_so_addr(so_addr);
+ if (FixupAddress(exe_so_addr)) {
+ if (line_table->FindLineEntryByAddress(exe_so_addr,
+ sc.line_entry)) {
+ resolved |= eSymbolContextLineEntry;
+ }
+ }
+ }
+ }
+
+ if (force_check_line_table && !(resolved & eSymbolContextLineEntry)) {
+ // We might have had a compile unit that had discontiguous address
+ // ranges where the gaps are symbols that don't have any debug info.
+ // Discontiguous compile unit address ranges should only happen when
+ // there aren't other functions from other compile units in these
+ // gaps. This helps keep the size of the aranges down.
+ sc.comp_unit = nullptr;
+ resolved &= ~eSymbolContextCompUnit;
+ }
+ } else {
+ GetObjectFile()->GetModule()->ReportWarning(
+ "{0:x16}: compile unit {1} failed to create a valid "
+ "lldb_private::CompileUnit class.",
+ cu_offset, cu_idx);
+ }
+ }
+ }
+ }
+ return resolved;
+}
+
+uint32_t SymbolFileDWARF::ResolveSymbolContext(
+ const SourceLocationSpec &src_location_spec,
+ SymbolContextItem resolve_scope, SymbolContextList &sc_list) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ const bool check_inlines = src_location_spec.GetCheckInlines();
+ const uint32_t prev_size = sc_list.GetSize();
+ if (resolve_scope & eSymbolContextCompUnit) {
+ for (uint32_t cu_idx = 0, num_cus = GetNumCompileUnits(); cu_idx < num_cus;
+ ++cu_idx) {
+ CompileUnit *dc_cu = ParseCompileUnitAtIndex(cu_idx).get();
+ if (!dc_cu)
+ continue;
+
+ bool file_spec_matches_cu_file_spec = FileSpec::Match(
+ src_location_spec.GetFileSpec(), dc_cu->GetPrimaryFile());
+ if (check_inlines || file_spec_matches_cu_file_spec) {
+ dc_cu->ResolveSymbolContext(src_location_spec, resolve_scope, sc_list);
+ if (!check_inlines)
+ break;
+ }
+ }
+ }
+ return sc_list.GetSize() - prev_size;
+}
+
+void SymbolFileDWARF::PreloadSymbols() {
+ // Get the symbol table for the symbol file prior to taking the module lock
+ // so that it is available without needing to take the module lock. The DWARF
+ // indexing might end up needing to relocate items when DWARF sections are
+ // loaded as they might end up getting the section contents which can call
+ // ObjectFileELF::RelocateSection() which in turn will ask for the symbol
+ // table and can cause deadlocks.
+ GetSymtab();
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ m_index->Preload();
+}
+
+std::recursive_mutex &SymbolFileDWARF::GetModuleMutex() const {
+ lldb::ModuleSP module_sp(m_debug_map_module_wp.lock());
+ if (module_sp)
+ return module_sp->GetMutex();
+ return GetObjectFile()->GetModule()->GetMutex();
+}
+
+bool SymbolFileDWARF::DeclContextMatchesThisSymbolFile(
+ const lldb_private::CompilerDeclContext &decl_ctx) {
+ if (!decl_ctx.IsValid()) {
+ // Invalid namespace decl which means we aren't matching only things in
+ // this symbol file, so return true to indicate it matches this symbol
+ // file.
+ return true;
+ }
+
+ TypeSystem *decl_ctx_type_system = decl_ctx.GetTypeSystem();
+ auto type_system_or_err = GetTypeSystemForLanguage(
+ decl_ctx_type_system->GetMinimumLanguage(nullptr));
+ if (auto err = type_system_or_err.takeError()) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Symbols), std::move(err),
+ "Unable to match namespace decl using TypeSystem: {0}");
+ return false;
+ }
+
+ if (decl_ctx_type_system == type_system_or_err->get())
+ return true; // The type systems match, return true
+
+ // The namespace AST was valid, and it does not match...
+ Log *log = GetLog(DWARFLog::Lookups);
+
+ if (log)
+ GetObjectFile()->GetModule()->LogMessage(
+ log, "Valid namespace does not match symbol file");
+
+ return false;
+}
+
+void SymbolFileDWARF::FindGlobalVariables(
+ ConstString name, const CompilerDeclContext &parent_decl_ctx,
+ uint32_t max_matches, VariableList &variables) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ Log *log = GetLog(DWARFLog::Lookups);
+
+ if (log)
+ GetObjectFile()->GetModule()->LogMessage(
+ log,
+ "SymbolFileDWARF::FindGlobalVariables (name=\"{0}\", "
+ "parent_decl_ctx={1:p}, max_matches={2}, variables)",
+ name.GetCString(), static_cast<const void *>(&parent_decl_ctx),
+ max_matches);
+
+ if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx))
+ return;
+
+ // Remember how many variables are in the list before we search.
+ const uint32_t original_size = variables.GetSize();
+
+ llvm::StringRef basename;
+ llvm::StringRef context;
+ bool name_is_mangled = Mangled::GetManglingScheme(name.GetStringRef()) !=
+ Mangled::eManglingSchemeNone;
+
+ if (!CPlusPlusLanguage::ExtractContextAndIdentifier(name.GetCString(),
+ context, basename))
+ basename = name.GetStringRef();
+
+ // Loop invariant: Variables up to this index have been checked for context
+ // matches.
+ uint32_t pruned_idx = original_size;
+
+ SymbolContext sc;
+ m_index->GetGlobalVariables(ConstString(basename), [&](DWARFDIE die) {
+ if (!sc.module_sp)
+ sc.module_sp = m_objfile_sp->GetModule();
+ assert(sc.module_sp);
+
+ if (die.Tag() != DW_TAG_variable)
+ return true;
+
+ auto *dwarf_cu = llvm::dyn_cast<DWARFCompileUnit>(die.GetCU());
+ if (!dwarf_cu)
+ return true;
+ sc.comp_unit = GetCompUnitForDWARFCompUnit(*dwarf_cu);
+
+ if (parent_decl_ctx) {
+ if (DWARFASTParser *dwarf_ast = GetDWARFParser(*die.GetCU())) {
+ CompilerDeclContext actual_parent_decl_ctx =
+ dwarf_ast->GetDeclContextContainingUIDFromDWARF(die);
+
+ /// If the actual namespace is inline (i.e., had a DW_AT_export_symbols)
+ /// and a child (possibly through other layers of inline namespaces)
+ /// of the namespace referred to by 'basename', allow the lookup to
+ /// succeed.
+ if (!actual_parent_decl_ctx ||
+ (actual_parent_decl_ctx != parent_decl_ctx &&
+ !parent_decl_ctx.IsContainedInLookup(actual_parent_decl_ctx)))
+ return true;
+ }
+ }
+
+ ParseAndAppendGlobalVariable(sc, die, variables);
+ while (pruned_idx < variables.GetSize()) {
+ VariableSP var_sp = variables.GetVariableAtIndex(pruned_idx);
+ if (name_is_mangled ||
+ var_sp->GetName().GetStringRef().contains(name.GetStringRef()))
+ ++pruned_idx;
+ else
+ variables.RemoveVariableAtIndex(pruned_idx);
+ }
+
+ return variables.GetSize() - original_size < max_matches;
+ });
+
+ // Return the number of variable that were appended to the list
+ const uint32_t num_matches = variables.GetSize() - original_size;
+ if (log && num_matches > 0) {
+ GetObjectFile()->GetModule()->LogMessage(
+ log,
+ "SymbolFileDWARF::FindGlobalVariables (name=\"{0}\", "
+ "parent_decl_ctx={1:p}, max_matches={2}, variables) => {3}",
+ name.GetCString(), static_cast<const void *>(&parent_decl_ctx),
+ max_matches, num_matches);
+ }
+}
+
+void SymbolFileDWARF::FindGlobalVariables(const RegularExpression &regex,
+ uint32_t max_matches,
+ VariableList &variables) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ Log *log = GetLog(DWARFLog::Lookups);
+
+ if (log) {
+ GetObjectFile()->GetModule()->LogMessage(
+ log,
+ "SymbolFileDWARF::FindGlobalVariables (regex=\"{0}\", "
+ "max_matches={1}, variables)",
+ regex.GetText().str().c_str(), max_matches);
+ }
+
+ // Remember how many variables are in the list before we search.
+ const uint32_t original_size = variables.GetSize();
+
+ SymbolContext sc;
+ m_index->GetGlobalVariables(regex, [&](DWARFDIE die) {
+ if (!sc.module_sp)
+ sc.module_sp = m_objfile_sp->GetModule();
+ assert(sc.module_sp);
+
+ DWARFCompileUnit *dwarf_cu = llvm::dyn_cast<DWARFCompileUnit>(die.GetCU());
+ if (!dwarf_cu)
+ return true;
+ sc.comp_unit = GetCompUnitForDWARFCompUnit(*dwarf_cu);
+
+ ParseAndAppendGlobalVariable(sc, die, variables);
+
+ return variables.GetSize() - original_size < max_matches;
+ });
+}
+
+bool SymbolFileDWARF::ResolveFunction(const DWARFDIE &orig_die,
+ bool include_inlines,
+ SymbolContextList &sc_list) {
+ SymbolContext sc;
+
+ if (!orig_die)
+ return false;
+
+ // If we were passed a die that is not a function, just return false...
+ if (!(orig_die.Tag() == DW_TAG_subprogram ||
+ (include_inlines && orig_die.Tag() == DW_TAG_inlined_subroutine)))
+ return false;
+
+ DWARFDIE die = orig_die;
+ DWARFDIE inlined_die;
+ if (die.Tag() == DW_TAG_inlined_subroutine) {
+ inlined_die = die;
+
+ while (true) {
+ die = die.GetParent();
+
+ if (die) {
+ if (die.Tag() == DW_TAG_subprogram)
+ break;
+ } else
+ break;
+ }
+ }
+ assert(die && die.Tag() == DW_TAG_subprogram);
+ if (GetFunction(die, sc)) {
+ Address addr;
+ // Parse all blocks if needed
+ if (inlined_die) {
+ Block &function_block = sc.function->GetBlock(true);
+ sc.block = function_block.FindBlockByID(inlined_die.GetID());
+ if (sc.block == nullptr)
+ sc.block = function_block.FindBlockByID(inlined_die.GetOffset());
+ if (sc.block == nullptr || !sc.block->GetStartAddress(addr))
+ addr.Clear();
+ } else {
+ sc.block = nullptr;
+ addr = sc.function->GetAddressRange().GetBaseAddress();
+ }
+
+ sc_list.Append(sc);
+ return true;
+ }
+
+ return false;
+}
+
+bool SymbolFileDWARF::DIEInDeclContext(const CompilerDeclContext &decl_ctx,
+ const DWARFDIE &die,
+ bool only_root_namespaces) {
+ // If we have no parent decl context to match this DIE matches, and if the
+ // parent decl context isn't valid, we aren't trying to look for any
+ // particular decl context so any die matches.
+ if (!decl_ctx.IsValid()) {
+ // ...But if we are only checking root decl contexts, confirm that the
+ // 'die' is a top-level context.
+ if (only_root_namespaces)
+ return die.GetParent().Tag() == llvm::dwarf::DW_TAG_compile_unit;
+
+ return true;
+ }
+
+ if (die) {
+ if (DWARFASTParser *dwarf_ast = GetDWARFParser(*die.GetCU())) {
+ if (CompilerDeclContext actual_decl_ctx =
+ dwarf_ast->GetDeclContextContainingUIDFromDWARF(die))
+ return decl_ctx.IsContainedInLookup(actual_decl_ctx);
+ }
+ }
+ return false;
+}
+
+void SymbolFileDWARF::FindFunctions(const Module::LookupInfo &lookup_info,
+ const CompilerDeclContext &parent_decl_ctx,
+ bool include_inlines,
+ SymbolContextList &sc_list) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ ConstString name = lookup_info.GetLookupName();
+ FunctionNameType name_type_mask = lookup_info.GetNameTypeMask();
+
+ // eFunctionNameTypeAuto should be pre-resolved by a call to
+ // Module::LookupInfo::LookupInfo()
+ assert((name_type_mask & eFunctionNameTypeAuto) == 0);
+
+ Log *log = GetLog(DWARFLog::Lookups);
+
+ if (log) {
+ GetObjectFile()->GetModule()->LogMessage(
+ log,
+ "SymbolFileDWARF::FindFunctions (name=\"{0}\", name_type_mask={1:x}, "
+ "sc_list)",
+ name.GetCString(), name_type_mask);
+ }
+
+ if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx))
+ return;
+
+ // If name is empty then we won't find anything.
+ if (name.IsEmpty())
+ return;
+
+ // Remember how many sc_list are in the list before we search in case we are
+ // appending the results to a variable list.
+
+ const uint32_t original_size = sc_list.GetSize();
+
+ llvm::DenseSet<const DWARFDebugInfoEntry *> resolved_dies;
+
+ m_index->GetFunctions(lookup_info, *this, parent_decl_ctx, [&](DWARFDIE die) {
+ if (resolved_dies.insert(die.GetDIE()).second)
+ ResolveFunction(die, include_inlines, sc_list);
+ return true;
+ });
+ // With -gsimple-template-names, a templated type's DW_AT_name will not
+ // contain the template parameters. Try again stripping '<' and anything
+ // after, filtering out entries with template parameters that don't match.
+ {
+ const llvm::StringRef name_ref = name.GetStringRef();
+ auto it = name_ref.find('<');
+ if (it != llvm::StringRef::npos) {
+ const llvm::StringRef name_no_template_params = name_ref.slice(0, it);
+
+ Module::LookupInfo no_tp_lookup_info(lookup_info);
+ no_tp_lookup_info.SetLookupName(ConstString(name_no_template_params));
+ m_index->GetFunctions(no_tp_lookup_info, *this, parent_decl_ctx,
+ [&](DWARFDIE die) {
+ if (resolved_dies.insert(die.GetDIE()).second)
+ ResolveFunction(die, include_inlines, sc_list);
+ return true;
+ });
+ }
+ }
+
+ // Return the number of variable that were appended to the list
+ const uint32_t num_matches = sc_list.GetSize() - original_size;
+
+ if (log && num_matches > 0) {
+ GetObjectFile()->GetModule()->LogMessage(
+ log,
+ "SymbolFileDWARF::FindFunctions (name=\"{0}\", "
+ "name_type_mask={1:x}, include_inlines={2:d}, sc_list) => {3}",
+ name.GetCString(), name_type_mask, include_inlines, num_matches);
+ }
+}
+
+void SymbolFileDWARF::FindFunctions(const RegularExpression &regex,
+ bool include_inlines,
+ SymbolContextList &sc_list) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ LLDB_SCOPED_TIMERF("SymbolFileDWARF::FindFunctions (regex = '%s')",
+ regex.GetText().str().c_str());
+
+ Log *log = GetLog(DWARFLog::Lookups);
+
+ if (log) {
+ GetObjectFile()->GetModule()->LogMessage(
+ log, "SymbolFileDWARF::FindFunctions (regex=\"{0}\", sc_list)",
+ regex.GetText().str().c_str());
+ }
+
+ llvm::DenseSet<const DWARFDebugInfoEntry *> resolved_dies;
+ m_index->GetFunctions(regex, [&](DWARFDIE die) {
+ if (resolved_dies.insert(die.GetDIE()).second)
+ ResolveFunction(die, include_inlines, sc_list);
+ return true;
+ });
+}
+
+void SymbolFileDWARF::GetMangledNamesForFunction(
+ const std::string &scope_qualified_name,
+ std::vector<ConstString> &mangled_names) {
+ DWARFDebugInfo &info = DebugInfo();
+ uint32_t num_comp_units = info.GetNumUnits();
+ for (uint32_t i = 0; i < num_comp_units; i++) {
+ DWARFUnit *cu = info.GetUnitAtIndex(i);
+ if (cu == nullptr)
+ continue;
+
+ SymbolFileDWARFDwo *dwo = cu->GetDwoSymbolFile();
+ if (dwo)
+ dwo->GetMangledNamesForFunction(scope_qualified_name, mangled_names);
+ }
+
+ for (DIERef die_ref :
+ m_function_scope_qualified_name_map.lookup(scope_qualified_name)) {
+ DWARFDIE die = GetDIE(die_ref);
+ mangled_names.push_back(ConstString(die.GetMangledName()));
+ }
+}
+
+/// Split a name up into a basename and template parameters.
+static bool SplitTemplateParams(llvm::StringRef fullname,
+ llvm::StringRef &basename,
+ llvm::StringRef &template_params) {
+ auto it = fullname.find('<');
+ if (it == llvm::StringRef::npos) {
+ basename = fullname;
+ template_params = llvm::StringRef();
+ return false;
+ }
+ basename = fullname.slice(0, it);
+ template_params = fullname.slice(it, fullname.size());
+ return true;
+}
+
+static bool UpdateCompilerContextForSimpleTemplateNames(TypeQuery &match) {
+ // We need to find any names in the context that have template parameters
+ // and strip them so the context can be matched when -gsimple-template-names
+ // is being used. Returns true if any of the context items were updated.
+ bool any_context_updated = false;
+ for (auto &context : match.GetContextRef()) {
+ llvm::StringRef basename, params;
+ if (SplitTemplateParams(context.name.GetStringRef(), basename, params)) {
+ context.name = ConstString(basename);
+ any_context_updated = true;
+ }
+ }
+ return any_context_updated;
+}
+
+uint64_t SymbolFileDWARF::GetDebugInfoSize(bool load_all_debug_info) {
+ DWARFDebugInfo &info = DebugInfo();
+ uint32_t num_comp_units = info.GetNumUnits();
+
+ uint64_t debug_info_size = SymbolFileCommon::GetDebugInfoSize();
+ // In dwp scenario, debug info == skeleton debug info + dwp debug info.
+ if (std::shared_ptr<SymbolFileDWARFDwo> dwp_sp = GetDwpSymbolFile())
+ return debug_info_size + dwp_sp->GetDebugInfoSize();
+
+ // In dwo scenario, debug info == skeleton debug info + all dwo debug info.
+ for (uint32_t i = 0; i < num_comp_units; i++) {
+ DWARFUnit *cu = info.GetUnitAtIndex(i);
+ if (cu == nullptr)
+ continue;
+
+ SymbolFileDWARFDwo *dwo = cu->GetDwoSymbolFile(load_all_debug_info);
+ if (dwo)
+ debug_info_size += dwo->GetDebugInfoSize();
+ }
+ return debug_info_size;
+}
+
+void SymbolFileDWARF::FindTypes(const TypeQuery &query, TypeResults &results) {
+
+ // Make sure we haven't already searched this SymbolFile before.
+ if (results.AlreadySearched(this))
+ return;
+
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+
+ bool have_index_match = false;
+ m_index->GetTypes(query.GetTypeBasename(), [&](DWARFDIE die) {
+ // Check the language, but only if we have a language filter.
+ if (query.HasLanguage()) {
+ if (!query.LanguageMatches(GetLanguageFamily(*die.GetCU())))
+ return true; // Keep iterating over index types, language mismatch.
+ }
+
+ // Check the context matches
+ std::vector<lldb_private::CompilerContext> die_context;
+ if (query.GetModuleSearch())
+ die_context = die.GetDeclContext();
+ else
+ die_context = die.GetTypeLookupContext();
+ assert(!die_context.empty());
+ if (!query.ContextMatches(die_context))
+ return true; // Keep iterating over index types, context mismatch.
+
+ // Try to resolve the type.
+ if (Type *matching_type = ResolveType(die, true, true)) {
+ if (matching_type->IsTemplateType()) {
+ // We have to watch out for case where we lookup a type by basename and
+ // it matches a template with simple template names. Like looking up
+ // "Foo" and if we have simple template names then we will match
+ // "Foo<int>" and "Foo<double>" because all the DWARF has is "Foo" in
+ // the accelerator tables. The main case we see this in is when the
+ // expression parser is trying to parse "Foo<int>" and it will first do
+ // a lookup on just "Foo". We verify the type basename matches before
+ // inserting the type in the results.
+ auto CompilerTypeBasename =
+ matching_type->GetForwardCompilerType().GetTypeName(true);
+ if (CompilerTypeBasename != query.GetTypeBasename())
+ return true; // Keep iterating over index types, basename mismatch.
+ }
+ have_index_match = true;
+ results.InsertUnique(matching_type->shared_from_this());
+ }
+ return !results.Done(query); // Keep iterating if we aren't done.
+ });
+
+ if (results.Done(query))
+ return;
+
+ // With -gsimple-template-names, a templated type's DW_AT_name will not
+ // contain the template parameters. Try again stripping '<' and anything
+ // after, filtering out entries with template parameters that don't match.
+ if (!have_index_match) {
+ // Create a type matcher with a compiler context that is tuned for
+ // -gsimple-template-names. We will use this for the index lookup and the
+ // context matching, but will use the original "match" to insert matches
+ // into if things match. The "match_simple" has a compiler context with
+ // all template parameters removed to allow the names and context to match.
+ // The UpdateCompilerContextForSimpleTemplateNames(...) will return true if
+ // it trims any context items down by removing template parameter names.
+ TypeQuery query_simple(query);
+ if (UpdateCompilerContextForSimpleTemplateNames(query_simple)) {
+
+ // Copy our match's context and update the basename we are looking for
+ // so we can use this only to compare the context correctly.
+ m_index->GetTypes(query_simple.GetTypeBasename(), [&](DWARFDIE die) {
+ // Check the language, but only if we have a language filter.
+ if (query.HasLanguage()) {
+ if (!query.LanguageMatches(GetLanguageFamily(*die.GetCU())))
+ return true; // Keep iterating over index types, language mismatch.
+ }
+
+ // Check the context matches
+ std::vector<lldb_private::CompilerContext> die_context;
+ if (query.GetModuleSearch())
+ die_context = die.GetDeclContext();
+ else
+ die_context = die.GetTypeLookupContext();
+ assert(!die_context.empty());
+ if (!query_simple.ContextMatches(die_context))
+ return true; // Keep iterating over index types, context mismatch.
+
+ // Try to resolve the type.
+ if (Type *matching_type = ResolveType(die, true, true)) {
+ ConstString name = matching_type->GetQualifiedName();
+ // We have found a type that still might not match due to template
+ // parameters. If we create a new TypeQuery that uses the new type's
+ // fully qualified name, we can find out if this type matches at all
+ // context levels. We can't use just the "match_simple" context
+ // because all template parameters were stripped off. The fully
+ // qualified name of the type will have the template parameters and
+ // will allow us to make sure it matches correctly.
+ TypeQuery die_query(name.GetStringRef(),
+ TypeQueryOptions::e_exact_match);
+ if (!query.ContextMatches(die_query.GetContextRef()))
+ return true; // Keep iterating over index types, context mismatch.
+
+ results.InsertUnique(matching_type->shared_from_this());
+ }
+ return !results.Done(query); // Keep iterating if we aren't done.
+ });
+ if (results.Done(query))
+ return;
+ }
+ }
+
+ // Next search through the reachable Clang modules. This only applies for
+ // DWARF objects compiled with -gmodules that haven't been processed by
+ // dsymutil.
+ UpdateExternalModuleListIfNeeded();
+
+ for (const auto &pair : m_external_type_modules) {
+ if (ModuleSP external_module_sp = pair.second) {
+ external_module_sp->FindTypes(query, results);
+ if (results.Done(query))
+ return;
+ }
+ }
+}
+
+CompilerDeclContext
+SymbolFileDWARF::FindNamespace(ConstString name,
+ const CompilerDeclContext &parent_decl_ctx,
+ bool only_root_namespaces) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ Log *log = GetLog(DWARFLog::Lookups);
+
+ if (log) {
+ GetObjectFile()->GetModule()->LogMessage(
+ log, "SymbolFileDWARF::FindNamespace (sc, name=\"{0}\")",
+ name.GetCString());
+ }
+
+ CompilerDeclContext namespace_decl_ctx;
+
+ if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx))
+ return namespace_decl_ctx;
+
+ m_index->GetNamespaces(name, [&](DWARFDIE die) {
+ if (!DIEInDeclContext(parent_decl_ctx, die, only_root_namespaces))
+ return true; // The containing decl contexts don't match
+
+ DWARFASTParser *dwarf_ast = GetDWARFParser(*die.GetCU());
+ if (!dwarf_ast)
+ return true;
+
+ namespace_decl_ctx = dwarf_ast->GetDeclContextForUIDFromDWARF(die);
+ return !namespace_decl_ctx.IsValid();
+ });
+
+ if (log && namespace_decl_ctx) {
+ GetObjectFile()->GetModule()->LogMessage(
+ log,
+ "SymbolFileDWARF::FindNamespace (sc, name=\"{0}\") => "
+ "CompilerDeclContext({1:p}/{2:p}) \"{3}\"",
+ name.GetCString(),
+ static_cast<const void *>(namespace_decl_ctx.GetTypeSystem()),
+ static_cast<const void *>(namespace_decl_ctx.GetOpaqueDeclContext()),
+ namespace_decl_ctx.GetName().AsCString("<NULL>"));
+ }
+
+ return namespace_decl_ctx;
+}
+
+TypeSP SymbolFileDWARF::GetTypeForDIE(const DWARFDIE &die,
+ bool resolve_function_context) {
+ TypeSP type_sp;
+ if (die) {
+ Type *type_ptr = GetDIEToType().lookup(die.GetDIE());
+ if (type_ptr == nullptr) {
+ SymbolContextScope *scope;
+ if (auto *dwarf_cu = llvm::dyn_cast<DWARFCompileUnit>(die.GetCU()))
+ scope = GetCompUnitForDWARFCompUnit(*dwarf_cu);
+ else
+ scope = GetObjectFile()->GetModule().get();
+ assert(scope);
+ SymbolContext sc(scope);
+ const DWARFDebugInfoEntry *parent_die = die.GetParent().GetDIE();
+ while (parent_die != nullptr) {
+ if (parent_die->Tag() == DW_TAG_subprogram)
+ break;
+ parent_die = parent_die->GetParent();
+ }
+ SymbolContext sc_backup = sc;
+ if (resolve_function_context && parent_die != nullptr &&
+ !GetFunction(DWARFDIE(die.GetCU(), parent_die), sc))
+ sc = sc_backup;
+
+ type_sp = ParseType(sc, die, nullptr);
+ } else if (type_ptr != DIE_IS_BEING_PARSED) {
+ // Get the original shared pointer for this type
+ type_sp = type_ptr->shared_from_this();
+ }
+ }
+ return type_sp;
+}
+
+DWARFDIE
+SymbolFileDWARF::GetDeclContextDIEContainingDIE(const DWARFDIE &orig_die) {
+ if (orig_die) {
+ DWARFDIE die = orig_die;
+
+ while (die) {
+ // If this is the original DIE that we are searching for a declaration
+ // for, then don't look in the cache as we don't want our own decl
+ // context to be our decl context...
+ if (orig_die != die) {
+ switch (die.Tag()) {
+ case DW_TAG_compile_unit:
+ case DW_TAG_partial_unit:
+ case DW_TAG_namespace:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_class_type:
+ case DW_TAG_lexical_block:
+ case DW_TAG_subprogram:
+ return die;
+ case DW_TAG_inlined_subroutine: {
+ DWARFDIE abs_die = die.GetReferencedDIE(DW_AT_abstract_origin);
+ if (abs_die) {
+ return abs_die;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ DWARFDIE spec_die = die.GetReferencedDIE(DW_AT_specification);
+ if (spec_die) {
+ DWARFDIE decl_ctx_die = GetDeclContextDIEContainingDIE(spec_die);
+ if (decl_ctx_die)
+ return decl_ctx_die;
+ }
+
+ DWARFDIE abs_die = die.GetReferencedDIE(DW_AT_abstract_origin);
+ if (abs_die) {
+ DWARFDIE decl_ctx_die = GetDeclContextDIEContainingDIE(abs_die);
+ if (decl_ctx_die)
+ return decl_ctx_die;
+ }
+
+ die = die.GetParent();
+ }
+ }
+ return DWARFDIE();
+}
+
+Symbol *SymbolFileDWARF::GetObjCClassSymbol(ConstString objc_class_name) {
+ Symbol *objc_class_symbol = nullptr;
+ if (m_objfile_sp) {
+ Symtab *symtab = m_objfile_sp->GetSymtab();
+ if (symtab) {
+ objc_class_symbol = symtab->FindFirstSymbolWithNameAndType(
+ objc_class_name, eSymbolTypeObjCClass, Symtab::eDebugNo,
+ Symtab::eVisibilityAny);
+ }
+ }
+ return objc_class_symbol;
+}
+
+// Some compilers don't emit the DW_AT_APPLE_objc_complete_type attribute. If
+// they don't then we can end up looking through all class types for a complete
+// type and never find the full definition. We need to know if this attribute
+// is supported, so we determine this here and cache th result. We also need to
+// worry about the debug map
+// DWARF file
+// if we are doing darwin DWARF in .o file debugging.
+bool SymbolFileDWARF::Supports_DW_AT_APPLE_objc_complete_type(DWARFUnit *cu) {
+ if (m_supports_DW_AT_APPLE_objc_complete_type == eLazyBoolCalculate) {
+ m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolNo;
+ if (cu && cu->Supports_DW_AT_APPLE_objc_complete_type())
+ m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolYes;
+ else {
+ DWARFDebugInfo &debug_info = DebugInfo();
+ const uint32_t num_compile_units = GetNumCompileUnits();
+ for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) {
+ DWARFUnit *dwarf_cu = debug_info.GetUnitAtIndex(cu_idx);
+ if (dwarf_cu != cu &&
+ dwarf_cu->Supports_DW_AT_APPLE_objc_complete_type()) {
+ m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolYes;
+ break;
+ }
+ }
+ }
+ if (m_supports_DW_AT_APPLE_objc_complete_type == eLazyBoolNo &&
+ GetDebugMapSymfile())
+ return m_debug_map_symfile->Supports_DW_AT_APPLE_objc_complete_type(this);
+ }
+ return m_supports_DW_AT_APPLE_objc_complete_type == eLazyBoolYes;
+}
+
+// This function can be used when a DIE is found that is a forward declaration
+// DIE and we want to try and find a type that has the complete definition.
+TypeSP SymbolFileDWARF::FindCompleteObjCDefinitionTypeForDIE(
+ const DWARFDIE &die, ConstString type_name, bool must_be_implementation) {
+
+ TypeSP type_sp;
+
+ if (!type_name || (must_be_implementation && !GetObjCClassSymbol(type_name)))
+ return type_sp;
+
+ m_index->GetCompleteObjCClass(
+ type_name, must_be_implementation, [&](DWARFDIE type_die) {
+ // Don't try and resolve the DIE we are looking for with the DIE
+ // itself!
+ if (type_die == die || !IsStructOrClassTag(type_die.Tag()))
+ return true;
+
+ if (must_be_implementation &&
+ type_die.Supports_DW_AT_APPLE_objc_complete_type()) {
+ const bool try_resolving_type = type_die.GetAttributeValueAsUnsigned(
+ DW_AT_APPLE_objc_complete_type, 0);
+ if (!try_resolving_type)
+ return true;
+ }
+
+ Type *resolved_type = ResolveType(type_die, false, true);
+ if (!resolved_type || resolved_type == DIE_IS_BEING_PARSED)
+ return true;
+
+ DEBUG_PRINTF(
+ "resolved 0x%8.8" PRIx64 " from %s to 0x%8.8" PRIx64
+ " (cu 0x%8.8" PRIx64 ")\n",
+ die.GetID(),
+ m_objfile_sp->GetFileSpec().GetFilename().AsCString("<Unknown>"),
+ type_die.GetID(), type_cu->GetID());
+
+ if (die)
+ GetDIEToType()[die.GetDIE()] = resolved_type;
+ type_sp = resolved_type->shared_from_this();
+ return false;
+ });
+ return type_sp;
+}
+
+DWARFDIE
+SymbolFileDWARF::FindDefinitionDIE(const DWARFDIE &die) {
+ const char *name = die.GetName();
+ if (!name)
+ return {};
+ if (!die.GetAttributeValueAsUnsigned(DW_AT_declaration, 0))
+ return die;
+
+ Progress progress(llvm::formatv(
+ "Searching definition DIE in {0}: '{1}'",
+ GetObjectFile()->GetFileSpec().GetFilename().GetString(), name));
+
+ const dw_tag_t tag = die.Tag();
+
+ Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups);
+ if (log) {
+ GetObjectFile()->GetModule()->LogMessage(
+ log,
+ "SymbolFileDWARF::FindDefinitionDIE(tag={0} "
+ "({1}), name='{2}')",
+ DW_TAG_value_to_name(tag), tag, name);
+ }
+
+ // Get the type system that we are looking to find a type for. We will
+ // use this to ensure any matches we find are in a language that this
+ // type system supports
+ const LanguageType language = GetLanguage(*die.GetCU());
+ TypeSystemSP type_system = nullptr;
+ if (language != eLanguageTypeUnknown) {
+ auto type_system_or_err = GetTypeSystemForLanguage(language);
+ if (auto err = type_system_or_err.takeError()) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Symbols), std::move(err),
+ "Cannot get TypeSystem for language {1}: {0}",
+ Language::GetNameForLanguageType(language));
+ } else {
+ type_system = *type_system_or_err;
+ }
+ }
+
+ // See comments below about -gsimple-template-names for why we attempt to
+ // compute missing template parameter names.
+ std::vector<std::string> template_params;
+ DWARFDeclContext die_dwarf_decl_ctx;
+ DWARFASTParser *dwarf_ast =
+ type_system ? type_system->GetDWARFParser() : nullptr;
+ for (DWARFDIE ctx_die = die; ctx_die && !isUnitType(ctx_die.Tag());
+ ctx_die = ctx_die.GetParentDeclContextDIE()) {
+ die_dwarf_decl_ctx.AppendDeclContext(ctx_die.Tag(), ctx_die.GetName());
+ template_params.push_back(
+ (ctx_die.IsStructUnionOrClass() && dwarf_ast)
+ ? dwarf_ast->GetDIEClassTemplateParams(ctx_die)
+ : "");
+ }
+ const bool any_template_params = llvm::any_of(
+ template_params, [](llvm::StringRef p) { return !p.empty(); });
+
+ auto die_matches = [&](DWARFDIE type_die) {
+ // Resolve the type if both have the same tag or {class, struct} tags.
+ const bool tag_matches =
+ type_die.Tag() == tag ||
+ (IsStructOrClassTag(type_die.Tag()) && IsStructOrClassTag(tag));
+ if (!tag_matches)
+ return false;
+ if (any_template_params) {
+ size_t pos = 0;
+ for (DWARFDIE ctx_die = type_die; ctx_die && !isUnitType(ctx_die.Tag()) &&
+ pos < template_params.size();
+ ctx_die = ctx_die.GetParentDeclContextDIE(), ++pos) {
+ if (template_params[pos].empty())
+ continue;
+ if (template_params[pos] !=
+ dwarf_ast->GetDIEClassTemplateParams(ctx_die))
+ return false;
+ }
+ if (pos != template_params.size())
+ return false;
+ }
+ return true;
+ };
+ DWARFDIE result;
+ m_index->GetFullyQualifiedType(die_dwarf_decl_ctx, [&](DWARFDIE type_die) {
+ // Make sure type_die's language matches the type system we are
+ // looking for. We don't want to find a "Foo" type from Java if we
+ // are looking for a "Foo" type for C, C++, ObjC, or ObjC++.
+ if (type_system &&
+ !type_system->SupportsLanguage(GetLanguage(*type_die.GetCU())))
+ return true;
+
+ if (!die_matches(type_die)) {
+ if (log) {
+ GetObjectFile()->GetModule()->LogMessage(
+ log,
+ "SymbolFileDWARF::FindDefinitionDIE(tag={0} ({1}), "
+ "name='{2}') ignoring die={3:x16} ({4})",
+ DW_TAG_value_to_name(tag), tag, name, type_die.GetOffset(),
+ type_die.GetName());
+ }
+ return true;
+ }
+
+ if (log) {
+ DWARFDeclContext type_dwarf_decl_ctx = type_die.GetDWARFDeclContext();
+ GetObjectFile()->GetModule()->LogMessage(
+ log,
+ "SymbolFileDWARF::FindDefinitionTypeDIE(tag={0} ({1}), name='{2}') "
+ "trying die={3:x16} ({4})",
+ DW_TAG_value_to_name(tag), tag, name, type_die.GetOffset(),
+ type_dwarf_decl_ctx.GetQualifiedName());
+ }
+
+ result = type_die;
+ return false;
+ });
+ return result;
+}
+
+TypeSP SymbolFileDWARF::ParseType(const SymbolContext &sc, const DWARFDIE &die,
+ bool *type_is_new_ptr) {
+ if (!die)
+ return {};
+
+ auto type_system_or_err = GetTypeSystemForLanguage(GetLanguage(*die.GetCU()));
+ if (auto err = type_system_or_err.takeError()) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Symbols), std::move(err),
+ "Unable to parse type: {0}");
+ return {};
+ }
+ auto ts = *type_system_or_err;
+ if (!ts)
+ return {};
+
+ DWARFASTParser *dwarf_ast = ts->GetDWARFParser();
+ if (!dwarf_ast)
+ return {};
+
+ TypeSP type_sp = dwarf_ast->ParseTypeFromDWARF(sc, die, type_is_new_ptr);
+ if (type_sp) {
+ if (die.Tag() == DW_TAG_subprogram) {
+ std::string scope_qualified_name(GetDeclContextForUID(die.GetID())
+ .GetScopeQualifiedName()
+ .AsCString(""));
+ if (scope_qualified_name.size()) {
+ m_function_scope_qualified_name_map[scope_qualified_name].insert(
+ *die.GetDIERef());
+ }
+ }
+ }
+
+ return type_sp;
+}
+
+size_t SymbolFileDWARF::ParseTypes(const SymbolContext &sc,
+ const DWARFDIE &orig_die,
+ bool parse_siblings, bool parse_children) {
+ size_t types_added = 0;
+ DWARFDIE die = orig_die;
+
+ while (die) {
+ const dw_tag_t tag = die.Tag();
+ bool type_is_new = false;
+
+ Tag dwarf_tag = static_cast<Tag>(tag);
+
+ // TODO: Currently ParseTypeFromDWARF(...) which is called by ParseType(...)
+ // does not handle DW_TAG_subrange_type. It is not clear if this is a bug or
+ // not.
+ if (isType(dwarf_tag) && tag != DW_TAG_subrange_type)
+ ParseType(sc, die, &type_is_new);
+
+ if (type_is_new)
+ ++types_added;
+
+ if (parse_children && die.HasChildren()) {
+ if (die.Tag() == DW_TAG_subprogram) {
+ SymbolContext child_sc(sc);
+ child_sc.function = sc.comp_unit->FindFunctionByUID(die.GetID()).get();
+ types_added += ParseTypes(child_sc, die.GetFirstChild(), true, true);
+ } else
+ types_added += ParseTypes(sc, die.GetFirstChild(), true, true);
+ }
+
+ if (parse_siblings)
+ die = die.GetSibling();
+ else
+ die.Clear();
+ }
+ return types_added;
+}
+
+size_t SymbolFileDWARF::ParseBlocksRecursive(Function &func) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ CompileUnit *comp_unit = func.GetCompileUnit();
+ lldbassert(comp_unit);
+
+ DWARFUnit *dwarf_cu = GetDWARFCompileUnit(comp_unit);
+ if (!dwarf_cu)
+ return 0;
+
+ size_t functions_added = 0;
+ const dw_offset_t function_die_offset = DIERef(func.GetID()).die_offset();
+ DWARFDIE function_die =
+ dwarf_cu->GetNonSkeletonUnit().GetDIE(function_die_offset);
+ if (function_die) {
+ ParseBlocksRecursive(*comp_unit, &func.GetBlock(false), function_die,
+ LLDB_INVALID_ADDRESS, 0);
+ }
+
+ return functions_added;
+}
+
+size_t SymbolFileDWARF::ParseTypes(CompileUnit &comp_unit) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ size_t types_added = 0;
+ DWARFUnit *dwarf_cu = GetDWARFCompileUnit(&comp_unit);
+ if (dwarf_cu) {
+ DWARFDIE dwarf_cu_die = dwarf_cu->DIE();
+ if (dwarf_cu_die && dwarf_cu_die.HasChildren()) {
+ SymbolContext sc;
+ sc.comp_unit = &comp_unit;
+ types_added = ParseTypes(sc, dwarf_cu_die.GetFirstChild(), true, true);
+ }
+ }
+
+ return types_added;
+}
+
+size_t SymbolFileDWARF::ParseVariablesForContext(const SymbolContext &sc) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ if (sc.comp_unit != nullptr) {
+ if (sc.function) {
+ DWARFDIE function_die = GetDIE(sc.function->GetID());
+
+ dw_addr_t func_lo_pc = LLDB_INVALID_ADDRESS;
+ DWARFRangeList ranges = function_die.GetDIE()->GetAttributeAddressRanges(
+ function_die.GetCU(), /*check_hi_lo_pc=*/true);
+ if (!ranges.IsEmpty())
+ func_lo_pc = ranges.GetMinRangeBase(0);
+ if (func_lo_pc != LLDB_INVALID_ADDRESS) {
+ const size_t num_variables =
+ ParseVariablesInFunctionContext(sc, function_die, func_lo_pc);
+
+ // Let all blocks know they have parse all their variables
+ sc.function->GetBlock(false).SetDidParseVariables(true, true);
+ return num_variables;
+ }
+ } else if (sc.comp_unit) {
+ DWARFUnit *dwarf_cu = DebugInfo().GetUnitAtIndex(sc.comp_unit->GetID());
+
+ if (dwarf_cu == nullptr)
+ return 0;
+
+ uint32_t vars_added = 0;
+ VariableListSP variables(sc.comp_unit->GetVariableList(false));
+
+ if (variables.get() == nullptr) {
+ variables = std::make_shared<VariableList>();
+ sc.comp_unit->SetVariableList(variables);
+
+ m_index->GetGlobalVariables(*dwarf_cu, [&](DWARFDIE die) {
+ VariableSP var_sp(ParseVariableDIECached(sc, die));
+ if (var_sp) {
+ variables->AddVariableIfUnique(var_sp);
+ ++vars_added;
+ }
+ return true;
+ });
+ }
+ return vars_added;
+ }
+ }
+ return 0;
+}
+
+VariableSP SymbolFileDWARF::ParseVariableDIECached(const SymbolContext &sc,
+ const DWARFDIE &die) {
+ if (!die)
+ return nullptr;
+
+ DIEToVariableSP &die_to_variable = die.GetDWARF()->GetDIEToVariable();
+
+ VariableSP var_sp = die_to_variable[die.GetDIE()];
+ if (var_sp)
+ return var_sp;
+
+ var_sp = ParseVariableDIE(sc, die, LLDB_INVALID_ADDRESS);
+ if (var_sp) {
+ die_to_variable[die.GetDIE()] = var_sp;
+ if (DWARFDIE spec_die = die.GetReferencedDIE(DW_AT_specification))
+ die_to_variable[spec_die.GetDIE()] = var_sp;
+ }
+ return var_sp;
+}
+
+/// Creates a DWARFExpressionList from an DW_AT_location form_value.
+static DWARFExpressionList GetExprListFromAtLocation(DWARFFormValue form_value,
+ ModuleSP module,
+ const DWARFDIE &die,
+ const addr_t func_low_pc) {
+ if (DWARFFormValue::IsBlockForm(form_value.Form())) {
+ const DWARFDataExtractor &data = die.GetData();
+
+ uint64_t block_offset = form_value.BlockData() - data.GetDataStart();
+ uint64_t block_length = form_value.Unsigned();
+ return DWARFExpressionList(
+ module, DataExtractor(data, block_offset, block_length), die.GetCU());
+ }
+
+ DWARFExpressionList location_list(module, DWARFExpression(), die.GetCU());
+ DataExtractor data = die.GetCU()->GetLocationData();
+ dw_offset_t offset = form_value.Unsigned();
+ if (form_value.Form() == DW_FORM_loclistx)
+ offset = die.GetCU()->GetLoclistOffset(offset).value_or(-1);
+ if (data.ValidOffset(offset)) {
+ data = DataExtractor(data, offset, data.GetByteSize() - offset);
+ const DWARFUnit *dwarf_cu = form_value.GetUnit();
+ if (DWARFExpression::ParseDWARFLocationList(dwarf_cu, data, &location_list))
+ location_list.SetFuncFileAddress(func_low_pc);
+ }
+
+ return location_list;
+}
+
+/// Creates a DWARFExpressionList from an DW_AT_const_value. This is either a
+/// block form, or a string, or a data form. For data forms, this returns an
+/// empty list, as we cannot initialize it properly without a SymbolFileType.
+static DWARFExpressionList
+GetExprListFromAtConstValue(DWARFFormValue form_value, ModuleSP module,
+ const DWARFDIE &die) {
+ const DWARFDataExtractor &debug_info_data = die.GetData();
+ if (DWARFFormValue::IsBlockForm(form_value.Form())) {
+ // Retrieve the value as a block expression.
+ uint64_t block_offset =
+ form_value.BlockData() - debug_info_data.GetDataStart();
+ uint64_t block_length = form_value.Unsigned();
+ return DWARFExpressionList(
+ module, DataExtractor(debug_info_data, block_offset, block_length),
+ die.GetCU());
+ }
+ if (const char *str = form_value.AsCString())
+ return DWARFExpressionList(module,
+ DataExtractor(str, strlen(str) + 1,
+ die.GetCU()->GetByteOrder(),
+ die.GetCU()->GetAddressByteSize()),
+ die.GetCU());
+ return DWARFExpressionList(module, DWARFExpression(), die.GetCU());
+}
+
+/// Global variables that are not initialized may have their address set to
+/// zero. Since multiple variables may have this address, we cannot apply the
+/// OSO relink address approach we normally use.
+/// However, the executable will have a matching symbol with a good address;
+/// this function attempts to find the correct address by looking into the
+/// executable's symbol table. If it succeeds, the expr_list is updated with
+/// the new address and the executable's symbol is returned.
+static Symbol *fixupExternalAddrZeroVariable(
+ SymbolFileDWARFDebugMap &debug_map_symfile, llvm::StringRef name,
+ DWARFExpressionList &expr_list, const DWARFDIE &die) {
+ ObjectFile *debug_map_objfile = debug_map_symfile.GetObjectFile();
+ if (!debug_map_objfile)
+ return nullptr;
+
+ Symtab *debug_map_symtab = debug_map_objfile->GetSymtab();
+ if (!debug_map_symtab)
+ return nullptr;
+ Symbol *exe_symbol = debug_map_symtab->FindFirstSymbolWithNameAndType(
+ ConstString(name), eSymbolTypeData, Symtab::eDebugYes,
+ Symtab::eVisibilityExtern);
+ if (!exe_symbol || !exe_symbol->ValueIsAddress())
+ return nullptr;
+ const addr_t exe_file_addr = exe_symbol->GetAddressRef().GetFileAddress();
+ if (exe_file_addr == LLDB_INVALID_ADDRESS)
+ return nullptr;
+
+ DWARFExpression *location = expr_list.GetMutableExpressionAtAddress();
+ if (location->Update_DW_OP_addr(die.GetCU(), exe_file_addr))
+ return exe_symbol;
+ return nullptr;
+}
+
+VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc,
+ const DWARFDIE &die,
+ const lldb::addr_t func_low_pc) {
+ if (die.GetDWARF() != this)
+ return die.GetDWARF()->ParseVariableDIE(sc, die, func_low_pc);
+
+ if (!die)
+ return nullptr;
+
+ const dw_tag_t tag = die.Tag();
+ ModuleSP module = GetObjectFile()->GetModule();
+
+ if (tag != DW_TAG_variable && tag != DW_TAG_constant &&
+ (tag != DW_TAG_formal_parameter || !sc.function))
+ return nullptr;
+
+ DWARFAttributes attributes = die.GetAttributes();
+ const char *name = nullptr;
+ const char *mangled = nullptr;
+ Declaration decl;
+ DWARFFormValue type_die_form;
+ bool is_external = false;
+ bool is_artificial = false;
+ DWARFFormValue const_value_form, location_form;
+ Variable::RangeList scope_ranges;
+
+ for (size_t i = 0; i < attributes.Size(); ++i) {
+ dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+
+ if (!attributes.ExtractFormValueAtIndex(i, form_value))
+ continue;
+ switch (attr) {
+ case DW_AT_decl_file:
+ decl.SetFile(
+ attributes.CompileUnitAtIndex(i)->GetFile(form_value.Unsigned()));
+ break;
+ case DW_AT_decl_line:
+ decl.SetLine(form_value.Unsigned());
+ break;
+ case DW_AT_decl_column:
+ decl.SetColumn(form_value.Unsigned());
+ break;
+ case DW_AT_name:
+ name = form_value.AsCString();
+ break;
+ case DW_AT_linkage_name:
+ case DW_AT_MIPS_linkage_name:
+ mangled = form_value.AsCString();
+ break;
+ case DW_AT_type:
+ type_die_form = form_value;
+ break;
+ case DW_AT_external:
+ is_external = form_value.Boolean();
+ break;
+ case DW_AT_const_value:
+ const_value_form = form_value;
+ break;
+ case DW_AT_location:
+ location_form = form_value;
+ break;
+ case DW_AT_start_scope:
+ // TODO: Implement this.
+ break;
+ case DW_AT_artificial:
+ is_artificial = form_value.Boolean();
+ break;
+ case DW_AT_declaration:
+ case DW_AT_description:
+ case DW_AT_endianity:
+ case DW_AT_segment:
+ case DW_AT_specification:
+ case DW_AT_visibility:
+ default:
+ case DW_AT_abstract_origin:
+ case DW_AT_sibling:
+ break;
+ }
+ }
+
+ // Prefer DW_AT_location over DW_AT_const_value. Both can be emitted e.g.
+ // for static constexpr member variables -- DW_AT_const_value and
+ // DW_AT_location will both be present in the DIE defining the member.
+ bool location_is_const_value_data =
+ const_value_form.IsValid() && !location_form.IsValid();
+
+ DWARFExpressionList location_list = [&] {
+ if (location_form.IsValid())
+ return GetExprListFromAtLocation(location_form, module, die, func_low_pc);
+ if (const_value_form.IsValid())
+ return GetExprListFromAtConstValue(const_value_form, module, die);
+ return DWARFExpressionList(module, DWARFExpression(), die.GetCU());
+ }();
+
+ const DWARFDIE parent_context_die = GetDeclContextDIEContainingDIE(die);
+ const DWARFDIE sc_parent_die = GetParentSymbolContextDIE(die);
+ const dw_tag_t parent_tag = sc_parent_die.Tag();
+ bool is_static_member = (parent_tag == DW_TAG_compile_unit ||
+ parent_tag == DW_TAG_partial_unit) &&
+ (parent_context_die.Tag() == DW_TAG_class_type ||
+ parent_context_die.Tag() == DW_TAG_structure_type);
+
+ ValueType scope = eValueTypeInvalid;
+ SymbolContextScope *symbol_context_scope = nullptr;
+
+ bool has_explicit_mangled = mangled != nullptr;
+ if (!mangled) {
+ // LLDB relies on the mangled name (DW_TAG_linkage_name or
+ // DW_AT_MIPS_linkage_name) to generate fully qualified names
+ // of global variables with commands like "frame var j". For
+ // example, if j were an int variable holding a value 4 and
+ // declared in a namespace B which in turn is contained in a
+ // namespace A, the command "frame var j" returns
+ // "(int) A::B::j = 4".
+ // If the compiler does not emit a linkage name, we should be
+ // able to generate a fully qualified name from the
+ // declaration context.
+ if ((parent_tag == DW_TAG_compile_unit ||
+ parent_tag == DW_TAG_partial_unit) &&
+ Language::LanguageIsCPlusPlus(GetLanguage(*die.GetCU())))
+ mangled = die.GetDWARFDeclContext()
+ .GetQualifiedNameAsConstString()
+ .GetCString();
+ }
+
+ if (tag == DW_TAG_formal_parameter)
+ scope = eValueTypeVariableArgument;
+ else {
+ // DWARF doesn't specify if a DW_TAG_variable is a local, global
+ // or static variable, so we have to do a little digging:
+ // 1) DW_AT_linkage_name implies static lifetime (but may be missing)
+ // 2) An empty DW_AT_location is an (optimized-out) static lifetime var.
+ // 3) DW_AT_location containing a DW_OP_addr implies static lifetime.
+ // Clang likes to combine small global variables into the same symbol
+ // with locations like: DW_OP_addr(0x1000), DW_OP_constu(2), DW_OP_plus
+ // so we need to look through the whole expression.
+ bool has_explicit_location = location_form.IsValid();
+ bool is_static_lifetime =
+ has_explicit_mangled ||
+ (has_explicit_location && !location_list.IsValid());
+ // Check if the location has a DW_OP_addr with any address value...
+ lldb::addr_t location_DW_OP_addr = LLDB_INVALID_ADDRESS;
+ if (!location_is_const_value_data) {
+ bool op_error = false;
+ const DWARFExpression* location = location_list.GetAlwaysValidExpr();
+ if (location)
+ location_DW_OP_addr =
+ location->GetLocation_DW_OP_addr(location_form.GetUnit(), op_error);
+ if (op_error) {
+ StreamString strm;
+ location->DumpLocation(&strm, eDescriptionLevelFull, nullptr);
+ GetObjectFile()->GetModule()->ReportError(
+ "{0:x16}: {1} ({2}) has an invalid location: {3}", die.GetOffset(),
+ DW_TAG_value_to_name(die.Tag()), die.Tag(), strm.GetData());
+ }
+ if (location_DW_OP_addr != LLDB_INVALID_ADDRESS)
+ is_static_lifetime = true;
+ }
+ SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile();
+ if (debug_map_symfile)
+ // Set the module of the expression to the linked module
+ // instead of the object file so the relocated address can be
+ // found there.
+ location_list.SetModule(debug_map_symfile->GetObjectFile()->GetModule());
+
+ if (is_static_lifetime) {
+ if (is_external)
+ scope = eValueTypeVariableGlobal;
+ else
+ scope = eValueTypeVariableStatic;
+
+ if (debug_map_symfile) {
+ bool linked_oso_file_addr = false;
+
+ if (is_external && location_DW_OP_addr == 0) {
+ if (Symbol *exe_symbol = fixupExternalAddrZeroVariable(
+ *debug_map_symfile, mangled ? mangled : name, location_list,
+ die)) {
+ linked_oso_file_addr = true;
+ symbol_context_scope = exe_symbol;
+ }
+ }
+
+ if (!linked_oso_file_addr) {
+ // The DW_OP_addr is not zero, but it contains a .o file address
+ // which needs to be linked up correctly.
+ const lldb::addr_t exe_file_addr =
+ debug_map_symfile->LinkOSOFileAddress(this, location_DW_OP_addr);
+ if (exe_file_addr != LLDB_INVALID_ADDRESS) {
+ // Update the file address for this variable
+ DWARFExpression *location =
+ location_list.GetMutableExpressionAtAddress();
+ location->Update_DW_OP_addr(die.GetCU(), exe_file_addr);
+ } else {
+ // Variable didn't make it into the final executable
+ return nullptr;
+ }
+ }
+ }
+ } else {
+ if (location_is_const_value_data &&
+ die.GetDIE()->IsGlobalOrStaticScopeVariable())
+ scope = eValueTypeVariableStatic;
+ else {
+ scope = eValueTypeVariableLocal;
+ if (debug_map_symfile) {
+ // We need to check for TLS addresses that we need to fixup
+ if (location_list.ContainsThreadLocalStorage()) {
+ location_list.LinkThreadLocalStorage(
+ debug_map_symfile->GetObjectFile()->GetModule(),
+ [this, debug_map_symfile](
+ lldb::addr_t unlinked_file_addr) -> lldb::addr_t {
+ return debug_map_symfile->LinkOSOFileAddress(
+ this, unlinked_file_addr);
+ });
+ scope = eValueTypeVariableThreadLocal;
+ }
+ }
+ }
+ }
+ }
+
+ if (symbol_context_scope == nullptr) {
+ switch (parent_tag) {
+ case DW_TAG_subprogram:
+ case DW_TAG_inlined_subroutine:
+ case DW_TAG_lexical_block:
+ if (sc.function) {
+ symbol_context_scope =
+ sc.function->GetBlock(true).FindBlockByID(sc_parent_die.GetID());
+ if (symbol_context_scope == nullptr)
+ symbol_context_scope = sc.function;
+ }
+ break;
+
+ default:
+ symbol_context_scope = sc.comp_unit;
+ break;
+ }
+ }
+
+ if (!symbol_context_scope) {
+ // Not ready to parse this variable yet. It might be a global or static
+ // variable that is in a function scope and the function in the symbol
+ // context wasn't filled in yet
+ return nullptr;
+ }
+
+ auto type_sp = std::make_shared<SymbolFileType>(
+ *this, type_die_form.Reference().GetID());
+
+ bool use_type_size_for_value =
+ location_is_const_value_data &&
+ DWARFFormValue::IsDataForm(const_value_form.Form());
+ if (use_type_size_for_value && type_sp->GetType()) {
+ DWARFExpression *location = location_list.GetMutableExpressionAtAddress();
+ location->UpdateValue(const_value_form.Unsigned(),
+ type_sp->GetType()->GetByteSize(nullptr).value_or(0),
+ die.GetCU()->GetAddressByteSize());
+ }
+
+ return std::make_shared<Variable>(
+ die.GetID(), name, mangled, type_sp, scope, symbol_context_scope,
+ scope_ranges, &decl, location_list, is_external, is_artificial,
+ location_is_const_value_data, is_static_member);
+}
+
+DWARFDIE
+SymbolFileDWARF::FindBlockContainingSpecification(
+ const DIERef &func_die_ref, dw_offset_t spec_block_die_offset) {
+ // Give the concrete function die specified by "func_die_offset", find the
+ // concrete block whose DW_AT_specification or DW_AT_abstract_origin points
+ // to "spec_block_die_offset"
+ return FindBlockContainingSpecification(GetDIE(func_die_ref),
+ spec_block_die_offset);
+}
+
+DWARFDIE
+SymbolFileDWARF::FindBlockContainingSpecification(
+ const DWARFDIE &die, dw_offset_t spec_block_die_offset) {
+ if (die) {
+ switch (die.Tag()) {
+ case DW_TAG_subprogram:
+ case DW_TAG_inlined_subroutine:
+ case DW_TAG_lexical_block: {
+ if (die.GetReferencedDIE(DW_AT_specification).GetOffset() ==
+ spec_block_die_offset)
+ return die;
+
+ if (die.GetReferencedDIE(DW_AT_abstract_origin).GetOffset() ==
+ spec_block_die_offset)
+ return die;
+ } break;
+ default:
+ break;
+ }
+
+ // Give the concrete function die specified by "func_die_offset", find the
+ // concrete block whose DW_AT_specification or DW_AT_abstract_origin points
+ // to "spec_block_die_offset"
+ for (DWARFDIE child_die : die.children()) {
+ DWARFDIE result_die =
+ FindBlockContainingSpecification(child_die, spec_block_die_offset);
+ if (result_die)
+ return result_die;
+ }
+ }
+
+ return DWARFDIE();
+}
+
+void SymbolFileDWARF::ParseAndAppendGlobalVariable(
+ const SymbolContext &sc, const DWARFDIE &die,
+ VariableList &cc_variable_list) {
+ if (!die)
+ return;
+
+ dw_tag_t tag = die.Tag();
+ if (tag != DW_TAG_variable && tag != DW_TAG_constant)
+ return;
+
+ // Check to see if we have already parsed this variable or constant?
+ VariableSP var_sp = GetDIEToVariable()[die.GetDIE()];
+ if (var_sp) {
+ cc_variable_list.AddVariableIfUnique(var_sp);
+ return;
+ }
+
+ // We haven't parsed the variable yet, lets do that now. Also, let us include
+ // the variable in the relevant compilation unit's variable list, if it
+ // exists.
+ VariableListSP variable_list_sp;
+ DWARFDIE sc_parent_die = GetParentSymbolContextDIE(die);
+ dw_tag_t parent_tag = sc_parent_die.Tag();
+ switch (parent_tag) {
+ case DW_TAG_compile_unit:
+ case DW_TAG_partial_unit:
+ if (sc.comp_unit != nullptr) {
+ variable_list_sp = sc.comp_unit->GetVariableList(false);
+ } else {
+ GetObjectFile()->GetModule()->ReportError(
+ "parent {0:x8} {1} ({2}) with no valid compile unit in "
+ "symbol context for {3:x8} {4} ({5}).\n",
+ sc_parent_die.GetID(), DW_TAG_value_to_name(sc_parent_die.Tag()),
+ sc_parent_die.Tag(), die.GetID(), DW_TAG_value_to_name(die.Tag()),
+ die.Tag());
+ return;
+ }
+ break;
+
+ default:
+ GetObjectFile()->GetModule()->ReportError(
+ "didn't find appropriate parent DIE for variable list for {0:x8} "
+ "{1} ({2}).\n",
+ die.GetID(), DW_TAG_value_to_name(die.Tag()), die.Tag());
+ return;
+ }
+
+ var_sp = ParseVariableDIECached(sc, die);
+ if (!var_sp)
+ return;
+
+ cc_variable_list.AddVariableIfUnique(var_sp);
+ if (variable_list_sp)
+ variable_list_sp->AddVariableIfUnique(var_sp);
+}
+
+DIEArray
+SymbolFileDWARF::MergeBlockAbstractParameters(const DWARFDIE &block_die,
+ DIEArray &&variable_dies) {
+ // DW_TAG_inline_subroutine objects may omit DW_TAG_formal_parameter in
+ // instances of the function when they are unused (i.e., the parameter's
+ // location list would be empty). The current DW_TAG_inline_subroutine may
+ // refer to another DW_TAG_subprogram that might actually have the definitions
+ // of the parameters and we need to include these so they show up in the
+ // variables for this function (for example, in a stack trace). Let us try to
+ // find the abstract subprogram that might contain the parameter definitions
+ // and merge with the concrete parameters.
+
+ // Nothing to merge if the block is not an inlined function.
+ if (block_die.Tag() != DW_TAG_inlined_subroutine) {
+ return std::move(variable_dies);
+ }
+
+ // Nothing to merge if the block does not have abstract parameters.
+ DWARFDIE abs_die = block_die.GetReferencedDIE(DW_AT_abstract_origin);
+ if (!abs_die || abs_die.Tag() != DW_TAG_subprogram ||
+ !abs_die.HasChildren()) {
+ return std::move(variable_dies);
+ }
+
+ // For each abstract parameter, if we have its concrete counterpart, insert
+ // it. Otherwise, insert the abstract parameter.
+ DIEArray::iterator concrete_it = variable_dies.begin();
+ DWARFDIE abstract_child = abs_die.GetFirstChild();
+ DIEArray merged;
+ bool did_merge_abstract = false;
+ for (; abstract_child; abstract_child = abstract_child.GetSibling()) {
+ if (abstract_child.Tag() == DW_TAG_formal_parameter) {
+ if (concrete_it == variable_dies.end() ||
+ GetDIE(*concrete_it).Tag() != DW_TAG_formal_parameter) {
+ // We arrived at the end of the concrete parameter list, so all
+ // the remaining abstract parameters must have been omitted.
+ // Let us insert them to the merged list here.
+ merged.push_back(*abstract_child.GetDIERef());
+ did_merge_abstract = true;
+ continue;
+ }
+
+ DWARFDIE origin_of_concrete =
+ GetDIE(*concrete_it).GetReferencedDIE(DW_AT_abstract_origin);
+ if (origin_of_concrete == abstract_child) {
+ // The current abstract parameter is the origin of the current
+ // concrete parameter, just push the concrete parameter.
+ merged.push_back(*concrete_it);
+ ++concrete_it;
+ } else {
+ // Otherwise, the parameter must have been omitted from the concrete
+ // function, so insert the abstract one.
+ merged.push_back(*abstract_child.GetDIERef());
+ did_merge_abstract = true;
+ }
+ }
+ }
+
+ // Shortcut if no merging happened.
+ if (!did_merge_abstract)
+ return std::move(variable_dies);
+
+ // We inserted all the abstract parameters (or their concrete counterparts).
+ // Let us insert all the remaining concrete variables to the merged list.
+ // During the insertion, let us check there are no remaining concrete
+ // formal parameters. If that's the case, then just bailout from the merge -
+ // the variable list is malformed.
+ for (; concrete_it != variable_dies.end(); ++concrete_it) {
+ if (GetDIE(*concrete_it).Tag() == DW_TAG_formal_parameter) {
+ return std::move(variable_dies);
+ }
+ merged.push_back(*concrete_it);
+ }
+ return merged;
+}
+
+size_t SymbolFileDWARF::ParseVariablesInFunctionContext(
+ const SymbolContext &sc, const DWARFDIE &die,
+ const lldb::addr_t func_low_pc) {
+ if (!die || !sc.function)
+ return 0;
+
+ DIEArray dummy_block_variables; // The recursive call should not add anything
+ // to this vector because |die| should be a
+ // subprogram, so all variables will be added
+ // to the subprogram's list.
+ return ParseVariablesInFunctionContextRecursive(sc, die, func_low_pc,
+ dummy_block_variables);
+}
+
+// This method parses all the variables in the blocks in the subtree of |die|,
+// and inserts them to the variable list for all the nested blocks.
+// The uninserted variables for the current block are accumulated in
+// |accumulator|.
+size_t SymbolFileDWARF::ParseVariablesInFunctionContextRecursive(
+ const lldb_private::SymbolContext &sc, const DWARFDIE &die,
+ lldb::addr_t func_low_pc, DIEArray &accumulator) {
+ size_t vars_added = 0;
+ dw_tag_t tag = die.Tag();
+
+ if ((tag == DW_TAG_variable) || (tag == DW_TAG_constant) ||
+ (tag == DW_TAG_formal_parameter)) {
+ accumulator.push_back(*die.GetDIERef());
+ }
+
+ switch (tag) {
+ case DW_TAG_subprogram:
+ case DW_TAG_inlined_subroutine:
+ case DW_TAG_lexical_block: {
+ // If we start a new block, compute a new block variable list and recurse.
+ Block *block =
+ sc.function->GetBlock(/*can_create=*/true).FindBlockByID(die.GetID());
+ if (block == nullptr) {
+ // This must be a specification or abstract origin with a
+ // concrete block counterpart in the current function. We need
+ // to find the concrete block so we can correctly add the
+ // variable to it.
+ const DWARFDIE concrete_block_die = FindBlockContainingSpecification(
+ GetDIE(sc.function->GetID()), die.GetOffset());
+ if (concrete_block_die)
+ block = sc.function->GetBlock(/*can_create=*/true)
+ .FindBlockByID(concrete_block_die.GetID());
+ }
+
+ if (block == nullptr)
+ return 0;
+
+ const bool can_create = false;
+ VariableListSP block_variable_list_sp =
+ block->GetBlockVariableList(can_create);
+ if (block_variable_list_sp.get() == nullptr) {
+ block_variable_list_sp = std::make_shared<VariableList>();
+ block->SetVariableList(block_variable_list_sp);
+ }
+
+ DIEArray block_variables;
+ for (DWARFDIE child = die.GetFirstChild(); child;
+ child = child.GetSibling()) {
+ vars_added += ParseVariablesInFunctionContextRecursive(
+ sc, child, func_low_pc, block_variables);
+ }
+ block_variables =
+ MergeBlockAbstractParameters(die, std::move(block_variables));
+ vars_added += PopulateBlockVariableList(*block_variable_list_sp, sc,
+ block_variables, func_low_pc);
+ break;
+ }
+
+ default:
+ // Recurse to children with the same variable accumulator.
+ for (DWARFDIE child = die.GetFirstChild(); child;
+ child = child.GetSibling()) {
+ vars_added += ParseVariablesInFunctionContextRecursive(
+ sc, child, func_low_pc, accumulator);
+ }
+ break;
+ }
+
+ return vars_added;
+}
+
+size_t SymbolFileDWARF::PopulateBlockVariableList(
+ VariableList &variable_list, const lldb_private::SymbolContext &sc,
+ llvm::ArrayRef<DIERef> variable_dies, lldb::addr_t func_low_pc) {
+ // Parse the variable DIEs and insert them to the list.
+ for (auto &die : variable_dies) {
+ if (VariableSP var_sp = ParseVariableDIE(sc, GetDIE(die), func_low_pc)) {
+ variable_list.AddVariableIfUnique(var_sp);
+ }
+ }
+ return variable_dies.size();
+}
+
+/// Collect call site parameters in a DW_TAG_call_site DIE.
+static CallSiteParameterArray
+CollectCallSiteParameters(ModuleSP module, DWARFDIE call_site_die) {
+ CallSiteParameterArray parameters;
+ for (DWARFDIE child : call_site_die.children()) {
+ if (child.Tag() != DW_TAG_call_site_parameter &&
+ child.Tag() != DW_TAG_GNU_call_site_parameter)
+ continue;
+
+ std::optional<DWARFExpressionList> LocationInCallee;
+ std::optional<DWARFExpressionList> LocationInCaller;
+
+ DWARFAttributes attributes = child.GetAttributes();
+
+ // Parse the location at index \p attr_index within this call site parameter
+ // DIE, or return std::nullopt on failure.
+ auto parse_simple_location =
+ [&](int attr_index) -> std::optional<DWARFExpressionList> {
+ DWARFFormValue form_value;
+ if (!attributes.ExtractFormValueAtIndex(attr_index, form_value))
+ return {};
+ if (!DWARFFormValue::IsBlockForm(form_value.Form()))
+ return {};
+ auto data = child.GetData();
+ uint64_t block_offset = form_value.BlockData() - data.GetDataStart();
+ uint64_t block_length = form_value.Unsigned();
+ return DWARFExpressionList(
+ module, DataExtractor(data, block_offset, block_length),
+ child.GetCU());
+ };
+
+ for (size_t i = 0; i < attributes.Size(); ++i) {
+ dw_attr_t attr = attributes.AttributeAtIndex(i);
+ if (attr == DW_AT_location)
+ LocationInCallee = parse_simple_location(i);
+ if (attr == DW_AT_call_value || attr == DW_AT_GNU_call_site_value)
+ LocationInCaller = parse_simple_location(i);
+ }
+
+ if (LocationInCallee && LocationInCaller) {
+ CallSiteParameter param = {*LocationInCallee, *LocationInCaller};
+ parameters.push_back(param);
+ }
+ }
+ return parameters;
+}
+
+/// Collect call graph edges present in a function DIE.
+std::vector<std::unique_ptr<lldb_private::CallEdge>>
+SymbolFileDWARF::CollectCallEdges(ModuleSP module, DWARFDIE function_die) {
+ // Check if the function has a supported call site-related attribute.
+ // TODO: In the future it may be worthwhile to support call_all_source_calls.
+ bool has_call_edges =
+ function_die.GetAttributeValueAsUnsigned(DW_AT_call_all_calls, 0) ||
+ function_die.GetAttributeValueAsUnsigned(DW_AT_GNU_all_call_sites, 0);
+ if (!has_call_edges)
+ return {};
+
+ Log *log = GetLog(LLDBLog::Step);
+ LLDB_LOG(log, "CollectCallEdges: Found call site info in {0}",
+ function_die.GetPubname());
+
+ // Scan the DIE for TAG_call_site entries.
+ // TODO: A recursive scan of all blocks in the subprogram is needed in order
+ // to be DWARF5-compliant. This may need to be done lazily to be performant.
+ // For now, assume that all entries are nested directly under the subprogram
+ // (this is the kind of DWARF LLVM produces) and parse them eagerly.
+ std::vector<std::unique_ptr<CallEdge>> call_edges;
+ for (DWARFDIE child : function_die.children()) {
+ if (child.Tag() != DW_TAG_call_site && child.Tag() != DW_TAG_GNU_call_site)
+ continue;
+
+ std::optional<DWARFDIE> call_origin;
+ std::optional<DWARFExpressionList> call_target;
+ addr_t return_pc = LLDB_INVALID_ADDRESS;
+ addr_t call_inst_pc = LLDB_INVALID_ADDRESS;
+ addr_t low_pc = LLDB_INVALID_ADDRESS;
+ bool tail_call = false;
+
+ // Second DW_AT_low_pc may come from DW_TAG_subprogram referenced by
+ // DW_TAG_GNU_call_site's DW_AT_abstract_origin overwriting our 'low_pc'.
+ // So do not inherit attributes from DW_AT_abstract_origin.
+ DWARFAttributes attributes = child.GetAttributes(DWARFDIE::Recurse::no);
+ for (size_t i = 0; i < attributes.Size(); ++i) {
+ DWARFFormValue form_value;
+ if (!attributes.ExtractFormValueAtIndex(i, form_value)) {
+ LLDB_LOG(log, "CollectCallEdges: Could not extract TAG_call_site form");
+ break;
+ }
+
+ dw_attr_t attr = attributes.AttributeAtIndex(i);
+
+ if (attr == DW_AT_call_tail_call || attr == DW_AT_GNU_tail_call)
+ tail_call = form_value.Boolean();
+
+ // Extract DW_AT_call_origin (the call target's DIE).
+ if (attr == DW_AT_call_origin || attr == DW_AT_abstract_origin) {
+ call_origin = form_value.Reference();
+ if (!call_origin->IsValid()) {
+ LLDB_LOG(log, "CollectCallEdges: Invalid call origin in {0}",
+ function_die.GetPubname());
+ break;
+ }
+ }
+
+ if (attr == DW_AT_low_pc)
+ low_pc = form_value.Address();
+
+ // Extract DW_AT_call_return_pc (the PC the call returns to) if it's
+ // available. It should only ever be unavailable for tail call edges, in
+ // which case use LLDB_INVALID_ADDRESS.
+ if (attr == DW_AT_call_return_pc)
+ return_pc = form_value.Address();
+
+ // Extract DW_AT_call_pc (the PC at the call/branch instruction). It
+ // should only ever be unavailable for non-tail calls, in which case use
+ // LLDB_INVALID_ADDRESS.
+ if (attr == DW_AT_call_pc)
+ call_inst_pc = form_value.Address();
+
+ // Extract DW_AT_call_target (the location of the address of the indirect
+ // call).
+ if (attr == DW_AT_call_target || attr == DW_AT_GNU_call_site_target) {
+ if (!DWARFFormValue::IsBlockForm(form_value.Form())) {
+ LLDB_LOG(log,
+ "CollectCallEdges: AT_call_target does not have block form");
+ break;
+ }
+
+ auto data = child.GetData();
+ uint64_t block_offset = form_value.BlockData() - data.GetDataStart();
+ uint64_t block_length = form_value.Unsigned();
+ call_target = DWARFExpressionList(
+ module, DataExtractor(data, block_offset, block_length),
+ child.GetCU());
+ }
+ }
+ if (!call_origin && !call_target) {
+ LLDB_LOG(log, "CollectCallEdges: call site without any call target");
+ continue;
+ }
+
+ addr_t caller_address;
+ CallEdge::AddrType caller_address_type;
+ if (return_pc != LLDB_INVALID_ADDRESS) {
+ caller_address = return_pc;
+ caller_address_type = CallEdge::AddrType::AfterCall;
+ } else if (low_pc != LLDB_INVALID_ADDRESS) {
+ caller_address = low_pc;
+ caller_address_type = CallEdge::AddrType::AfterCall;
+ } else if (call_inst_pc != LLDB_INVALID_ADDRESS) {
+ caller_address = call_inst_pc;
+ caller_address_type = CallEdge::AddrType::Call;
+ } else {
+ LLDB_LOG(log, "CollectCallEdges: No caller address");
+ continue;
+ }
+ // Adjust any PC forms. It needs to be fixed up if the main executable
+ // contains a debug map (i.e. pointers to object files), because we need a
+ // file address relative to the executable's text section.
+ caller_address = FixupAddress(caller_address);
+
+ // Extract call site parameters.
+ CallSiteParameterArray parameters =
+ CollectCallSiteParameters(module, child);
+
+ std::unique_ptr<CallEdge> edge;
+ if (call_origin) {
+ LLDB_LOG(log,
+ "CollectCallEdges: Found call origin: {0} (retn-PC: {1:x}) "
+ "(call-PC: {2:x})",
+ call_origin->GetPubname(), return_pc, call_inst_pc);
+ edge = std::make_unique<DirectCallEdge>(
+ call_origin->GetMangledName(), caller_address_type, caller_address,
+ tail_call, std::move(parameters));
+ } else {
+ if (log) {
+ StreamString call_target_desc;
+ call_target->GetDescription(&call_target_desc, eDescriptionLevelBrief,
+ nullptr);
+ LLDB_LOG(log, "CollectCallEdges: Found indirect call target: {0}",
+ call_target_desc.GetString());
+ }
+ edge = std::make_unique<IndirectCallEdge>(
+ *call_target, caller_address_type, caller_address, tail_call,
+ std::move(parameters));
+ }
+
+ if (log && parameters.size()) {
+ for (const CallSiteParameter &param : parameters) {
+ StreamString callee_loc_desc, caller_loc_desc;
+ param.LocationInCallee.GetDescription(&callee_loc_desc,
+ eDescriptionLevelBrief, nullptr);
+ param.LocationInCaller.GetDescription(&caller_loc_desc,
+ eDescriptionLevelBrief, nullptr);
+ LLDB_LOG(log, "CollectCallEdges: \tparam: {0} => {1}",
+ callee_loc_desc.GetString(), caller_loc_desc.GetString());
+ }
+ }
+
+ call_edges.push_back(std::move(edge));
+ }
+ return call_edges;
+}
+
+std::vector<std::unique_ptr<lldb_private::CallEdge>>
+SymbolFileDWARF::ParseCallEdgesInFunction(lldb_private::UserID func_id) {
+ // ParseCallEdgesInFunction must be called at the behest of an exclusively
+ // locked lldb::Function instance. Storage for parsed call edges is owned by
+ // the lldb::Function instance: locking at the SymbolFile level would be too
+ // late, because the act of storing results from ParseCallEdgesInFunction
+ // would be racy.
+ DWARFDIE func_die = GetDIE(func_id.GetID());
+ if (func_die.IsValid())
+ return CollectCallEdges(GetObjectFile()->GetModule(), func_die);
+ return {};
+}
+
+void SymbolFileDWARF::Dump(lldb_private::Stream &s) {
+ SymbolFileCommon::Dump(s);
+ m_index->Dump(s);
+}
+
+void SymbolFileDWARF::DumpClangAST(Stream &s) {
+ auto ts_or_err = GetTypeSystemForLanguage(eLanguageTypeC_plus_plus);
+ if (!ts_or_err)
+ return;
+ auto ts = *ts_or_err;
+ TypeSystemClang *clang = llvm::dyn_cast_or_null<TypeSystemClang>(ts.get());
+ if (!clang)
+ return;
+ clang->Dump(s.AsRawOstream());
+}
+
+bool SymbolFileDWARF::GetSeparateDebugInfo(StructuredData::Dictionary &d,
+ bool errors_only) {
+ StructuredData::Array separate_debug_info_files;
+ DWARFDebugInfo &info = DebugInfo();
+ const size_t num_cus = info.GetNumUnits();
+ for (size_t cu_idx = 0; cu_idx < num_cus; cu_idx++) {
+ DWARFUnit *unit = info.GetUnitAtIndex(cu_idx);
+ DWARFCompileUnit *dwarf_cu = llvm::dyn_cast<DWARFCompileUnit>(unit);
+ if (dwarf_cu == nullptr)
+ continue;
+
+ // Check if this is a DWO unit by checking if it has a DWO ID.
+ // NOTE: it seems that `DWARFUnit::IsDWOUnit` is always false?
+ if (!dwarf_cu->GetDWOId().has_value())
+ continue;
+
+ StructuredData::DictionarySP dwo_data =
+ std::make_shared<StructuredData::Dictionary>();
+ const uint64_t dwo_id = dwarf_cu->GetDWOId().value();
+ dwo_data->AddIntegerItem("dwo_id", dwo_id);
+
+ if (const DWARFBaseDIE die = dwarf_cu->GetUnitDIEOnly()) {
+ const char *dwo_name = GetDWOName(*dwarf_cu, *die.GetDIE());
+ if (dwo_name) {
+ dwo_data->AddStringItem("dwo_name", dwo_name);
+ } else {
+ dwo_data->AddStringItem("error", "missing dwo name");
+ }
+
+ const char *comp_dir = die.GetDIE()->GetAttributeValueAsString(
+ dwarf_cu, DW_AT_comp_dir, nullptr);
+ if (comp_dir) {
+ dwo_data->AddStringItem("comp_dir", comp_dir);
+ }
+ } else {
+ dwo_data->AddStringItem(
+ "error",
+ llvm::formatv("unable to get unit DIE for DWARFUnit at {0:x}",
+ dwarf_cu->GetOffset())
+ .str());
+ }
+
+ // If we have a DWO symbol file, that means we were able to successfully
+ // load it.
+ SymbolFile *dwo_symfile = dwarf_cu->GetDwoSymbolFile();
+ if (dwo_symfile) {
+ dwo_data->AddStringItem(
+ "resolved_dwo_path",
+ dwo_symfile->GetObjectFile()->GetFileSpec().GetPath());
+ } else {
+ dwo_data->AddStringItem("error",
+ dwarf_cu->GetDwoError().AsCString("unknown"));
+ }
+ dwo_data->AddBooleanItem("loaded", dwo_symfile != nullptr);
+ if (!errors_only || dwo_data->HasKey("error"))
+ separate_debug_info_files.AddItem(dwo_data);
+ }
+
+ d.AddStringItem("type", "dwo");
+ d.AddStringItem("symfile", GetMainObjectFile()->GetFileSpec().GetPath());
+ d.AddItem("separate-debug-info-files",
+ std::make_shared<StructuredData::Array>(
+ std::move(separate_debug_info_files)));
+ return true;
+}
+
+SymbolFileDWARFDebugMap *SymbolFileDWARF::GetDebugMapSymfile() {
+ if (m_debug_map_symfile == nullptr) {
+ lldb::ModuleSP module_sp(m_debug_map_module_wp.lock());
+ if (module_sp) {
+ m_debug_map_symfile = llvm::cast<SymbolFileDWARFDebugMap>(
+ module_sp->GetSymbolFile()->GetBackingSymbolFile());
+ }
+ }
+ return m_debug_map_symfile;
+}
+
+const std::shared_ptr<SymbolFileDWARFDwo> &SymbolFileDWARF::GetDwpSymbolFile() {
+ llvm::call_once(m_dwp_symfile_once_flag, [this]() {
+ // Create a list of files to try and append .dwp to.
+ FileSpecList symfiles;
+ // Append the module's object file path.
+ const FileSpec module_fspec = m_objfile_sp->GetModule()->GetFileSpec();
+ symfiles.Append(module_fspec);
+ // Append the object file for this SymbolFile only if it is different from
+ // the module's file path. Our main module could be "a.out", our symbol file
+ // could be "a.debug" and our ".dwp" file might be "a.debug.dwp" instead of
+ // "a.out.dwp".
+ const FileSpec symfile_fspec(m_objfile_sp->GetFileSpec());
+ if (symfile_fspec != module_fspec) {
+ symfiles.Append(symfile_fspec);
+ } else {
+ // If we don't have a separate debug info file, then try stripping the
+ // extension. The main module could be "a.debug" and the .dwp file could
+ // be "a.dwp" instead of "a.debug.dwp".
+ ConstString filename_no_ext =
+ module_fspec.GetFileNameStrippingExtension();
+ if (filename_no_ext != module_fspec.GetFilename()) {
+ FileSpec module_spec_no_ext(module_fspec);
+ module_spec_no_ext.SetFilename(filename_no_ext);
+ symfiles.Append(module_spec_no_ext);
+ }
+ }
+ Log *log = GetLog(DWARFLog::SplitDwarf);
+ FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths();
+ ModuleSpec module_spec;
+ module_spec.GetFileSpec() = m_objfile_sp->GetFileSpec();
+ for (const auto &symfile : symfiles.files()) {
+ module_spec.GetSymbolFileSpec() =
+ FileSpec(symfile.GetPath() + ".dwp", symfile.GetPathStyle());
+ LLDB_LOG(log, "Searching for DWP using: \"{0}\"",
+ module_spec.GetSymbolFileSpec());
+ FileSpec dwp_filespec =
+ PluginManager::LocateExecutableSymbolFile(module_spec, search_paths);
+ if (FileSystem::Instance().Exists(dwp_filespec)) {
+ LLDB_LOG(log, "Found DWP file: \"{0}\"", dwp_filespec);
+ DataBufferSP dwp_file_data_sp;
+ lldb::offset_t dwp_file_data_offset = 0;
+ ObjectFileSP dwp_obj_file = ObjectFile::FindPlugin(
+ GetObjectFile()->GetModule(), &dwp_filespec, 0,
+ FileSystem::Instance().GetByteSize(dwp_filespec), dwp_file_data_sp,
+ dwp_file_data_offset);
+ if (dwp_obj_file) {
+ m_dwp_symfile = std::make_shared<SymbolFileDWARFDwo>(
+ *this, dwp_obj_file, DIERef::k_file_index_mask);
+ break;
+ }
+ }
+ }
+ if (!m_dwp_symfile) {
+ LLDB_LOG(log, "Unable to locate for DWP file for: \"{0}\"",
+ m_objfile_sp->GetModule()->GetFileSpec());
+ }
+ });
+ return m_dwp_symfile;
+}
+
+llvm::Expected<lldb::TypeSystemSP>
+SymbolFileDWARF::GetTypeSystem(DWARFUnit &unit) {
+ return unit.GetSymbolFileDWARF().GetTypeSystemForLanguage(GetLanguage(unit));
+}
+
+DWARFASTParser *SymbolFileDWARF::GetDWARFParser(DWARFUnit &unit) {
+ auto type_system_or_err = GetTypeSystem(unit);
+ if (auto err = type_system_or_err.takeError()) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Symbols), std::move(err),
+ "Unable to get DWARFASTParser: {0}");
+ return nullptr;
+ }
+ if (auto ts = *type_system_or_err)
+ return ts->GetDWARFParser();
+ return nullptr;
+}
+
+CompilerDecl SymbolFileDWARF::GetDecl(const DWARFDIE &die) {
+ if (DWARFASTParser *dwarf_ast = GetDWARFParser(*die.GetCU()))
+ return dwarf_ast->GetDeclForUIDFromDWARF(die);
+ return CompilerDecl();
+}
+
+CompilerDeclContext SymbolFileDWARF::GetDeclContext(const DWARFDIE &die) {
+ if (DWARFASTParser *dwarf_ast = GetDWARFParser(*die.GetCU()))
+ return dwarf_ast->GetDeclContextForUIDFromDWARF(die);
+ return CompilerDeclContext();
+}
+
+CompilerDeclContext
+SymbolFileDWARF::GetContainingDeclContext(const DWARFDIE &die) {
+ if (DWARFASTParser *dwarf_ast = GetDWARFParser(*die.GetCU()))
+ return dwarf_ast->GetDeclContextContainingUIDFromDWARF(die);
+ return CompilerDeclContext();
+}
+
+LanguageType SymbolFileDWARF::LanguageTypeFromDWARF(uint64_t val) {
+ // Note: user languages between lo_user and hi_user must be handled
+ // explicitly here.
+ switch (val) {
+ case DW_LANG_Mips_Assembler:
+ return eLanguageTypeMipsAssembler;
+ default:
+ return static_cast<LanguageType>(val);
+ }
+}
+
+LanguageType SymbolFileDWARF::GetLanguage(DWARFUnit &unit) {
+ return LanguageTypeFromDWARF(unit.GetDWARFLanguageType());
+}
+
+LanguageType SymbolFileDWARF::GetLanguageFamily(DWARFUnit &unit) {
+ auto lang = (llvm::dwarf::SourceLanguage)unit.GetDWARFLanguageType();
+ if (llvm::dwarf::isCPlusPlus(lang))
+ lang = DW_LANG_C_plus_plus;
+ return LanguageTypeFromDWARF(lang);
+}
+
+StatsDuration::Duration SymbolFileDWARF::GetDebugInfoIndexTime() {
+ if (m_index)
+ return m_index->GetIndexTime();
+ return {};
+}
+
+Status SymbolFileDWARF::CalculateFrameVariableError(StackFrame &frame) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ CompileUnit *cu = frame.GetSymbolContext(eSymbolContextCompUnit).comp_unit;
+ if (!cu)
+ return Status();
+
+ DWARFCompileUnit *dwarf_cu = GetDWARFCompileUnit(cu);
+ if (!dwarf_cu)
+ return Status();
+
+ // Check if we have a skeleton compile unit that had issues trying to load
+ // its .dwo/.dwp file. First pares the Unit DIE to make sure we see any .dwo
+ // related errors.
+ dwarf_cu->ExtractUnitDIEIfNeeded();
+ const Status &dwo_error = dwarf_cu->GetDwoError();
+ if (dwo_error.Fail())
+ return dwo_error;
+
+ // Don't return an error for assembly files as they typically don't have
+ // varaible information.
+ if (dwarf_cu->GetDWARFLanguageType() == DW_LANG_Mips_Assembler)
+ return Status();
+
+ // Check if this compile unit has any variable DIEs. If it doesn't then there
+ // is not variable information for the entire compile unit.
+ if (dwarf_cu->HasAny({DW_TAG_variable, DW_TAG_formal_parameter}))
+ return Status();
+
+ return Status("no variable information is available in debug info for this "
+ "compile unit");
+}
+
+void SymbolFileDWARF::GetCompileOptions(
+ std::unordered_map<lldb::CompUnitSP, lldb_private::Args> &args) {
+
+ const uint32_t num_compile_units = GetNumCompileUnits();
+
+ for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) {
+ lldb::CompUnitSP comp_unit = GetCompileUnitAtIndex(cu_idx);
+ if (!comp_unit)
+ continue;
+
+ DWARFUnit *dwarf_cu = GetDWARFCompileUnit(comp_unit.get());
+ if (!dwarf_cu)
+ continue;
+
+ const DWARFBaseDIE die = dwarf_cu->GetUnitDIEOnly();
+ if (!die)
+ continue;
+
+ const char *flags = die.GetAttributeValueAsString(DW_AT_APPLE_flags, NULL);
+
+ if (!flags)
+ continue;
+ args.insert({comp_unit, Args(flags)});
+ }
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
new file mode 100644
index 000000000000..4967b37d753a
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -0,0 +1,565 @@
+//===-- SymbolFileDWARF.h --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_SYMBOLFILEDWARF_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_SYMBOLFILEDWARF_H
+
+#include <list>
+#include <map>
+#include <mutex>
+#include <optional>
+#include <unordered_map>
+#include <vector>
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/Support/Threading.h"
+
+#include "lldb/Core/UniqueCStringMap.h"
+#include "lldb/Core/dwarf.h"
+#include "lldb/Expression/DWARFExpressionList.h"
+#include "lldb/Symbol/DebugMacros.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Target/Statistics.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Flags.h"
+#include "lldb/Utility/RangeMap.h"
+#include "lldb/Utility/StructuredData.h"
+#include "lldb/lldb-private.h"
+
+#include "DWARFContext.h"
+#include "DWARFDataExtractor.h"
+#include "DWARFDefines.h"
+#include "DWARFIndex.h"
+#include "UniqueDWARFASTType.h"
+
+class DWARFASTParserClang;
+
+namespace llvm {
+class DWARFDebugAbbrev;
+} // namespace llvm
+
+namespace lldb_private::plugin {
+namespace dwarf {
+// Forward Declarations for this DWARF plugin
+class DebugMapModule;
+class DWARFCompileUnit;
+class DWARFDebugAranges;
+class DWARFDebugInfo;
+class DWARFDebugInfoEntry;
+class DWARFDebugLine;
+class DWARFDebugRanges;
+class DWARFDeclContext;
+class DWARFFormValue;
+class DWARFTypeUnit;
+class SymbolFileDWARFDebugMap;
+class SymbolFileDWARFDwo;
+class SymbolFileDWARFDwp;
+
+#define DIE_IS_BEING_PARSED ((lldb_private::Type *)1)
+
+class SymbolFileDWARF : public SymbolFileCommon {
+ /// LLVM RTTI support.
+ static char ID;
+
+public:
+ /// LLVM RTTI support.
+ /// \{
+ bool isA(const void *ClassID) const override {
+ return ClassID == &ID || SymbolFileCommon::isA(ClassID);
+ }
+ static bool classof(const SymbolFile *obj) { return obj->isA(&ID); }
+ /// \}
+
+ friend class SymbolFileDWARFDebugMap;
+ friend class SymbolFileDWARFDwo;
+ friend class DebugMapModule;
+ friend class DWARFCompileUnit;
+ friend class DWARFDIE;
+ friend class DWARFASTParser;
+
+ // Static Functions
+ static void Initialize();
+
+ static void Terminate();
+
+ static void DebuggerInitialize(Debugger &debugger);
+
+ static llvm::StringRef GetPluginNameStatic() { return "dwarf"; }
+
+ static llvm::StringRef GetPluginDescriptionStatic();
+
+ static SymbolFile *CreateInstance(lldb::ObjectFileSP objfile_sp);
+
+ // Constructors and Destructors
+
+ SymbolFileDWARF(lldb::ObjectFileSP objfile_sp, SectionList *dwo_section_list);
+
+ ~SymbolFileDWARF() override;
+
+ uint32_t CalculateAbilities() override;
+
+ void InitializeObject() override;
+
+ // Compile Unit function calls
+
+ lldb::LanguageType ParseLanguage(CompileUnit &comp_unit) override;
+
+ XcodeSDK ParseXcodeSDK(CompileUnit &comp_unit) override;
+
+ size_t ParseFunctions(CompileUnit &comp_unit) override;
+
+ bool ParseLineTable(CompileUnit &comp_unit) override;
+
+ bool ParseDebugMacros(CompileUnit &comp_unit) override;
+
+ bool ForEachExternalModule(CompileUnit &, llvm::DenseSet<SymbolFile *> &,
+ llvm::function_ref<bool(Module &)>) override;
+
+ bool ParseSupportFiles(CompileUnit &comp_unit,
+ SupportFileList &support_files) override;
+
+ bool ParseIsOptimized(CompileUnit &comp_unit) override;
+
+ size_t ParseTypes(CompileUnit &comp_unit) override;
+
+ bool
+ ParseImportedModules(const SymbolContext &sc,
+ std::vector<SourceModule> &imported_modules) override;
+
+ size_t ParseBlocksRecursive(Function &func) override;
+
+ size_t ParseVariablesForContext(const SymbolContext &sc) override;
+
+ std::optional<ArrayInfo>
+ GetDynamicArrayInfoForUID(lldb::user_id_t type_uid,
+ const ExecutionContext *exe_ctx) override;
+
+ bool CompleteType(CompilerType &compiler_type) override;
+
+ Type *ResolveType(const DWARFDIE &die, bool assert_not_being_parsed = true,
+ bool resolve_function_context = false);
+
+ CompilerDecl GetDeclForUID(lldb::user_id_t uid) override;
+
+ CompilerDeclContext GetDeclContextForUID(lldb::user_id_t uid) override;
+
+ CompilerDeclContext GetDeclContextContainingUID(lldb::user_id_t uid) override;
+
+ std::vector<CompilerContext>
+ GetCompilerContextForUID(lldb::user_id_t uid) override;
+
+ void ParseDeclsForContext(CompilerDeclContext decl_ctx) override;
+
+ uint32_t ResolveSymbolContext(const Address &so_addr,
+ lldb::SymbolContextItem resolve_scope,
+ SymbolContext &sc) override;
+
+ Status CalculateFrameVariableError(StackFrame &frame) override;
+
+ uint32_t ResolveSymbolContext(const SourceLocationSpec &src_location_spec,
+ lldb::SymbolContextItem resolve_scope,
+ SymbolContextList &sc_list) override;
+
+ void FindGlobalVariables(ConstString name,
+ const CompilerDeclContext &parent_decl_ctx,
+ uint32_t max_matches,
+ VariableList &variables) override;
+
+ void FindGlobalVariables(const RegularExpression &regex, uint32_t max_matches,
+ VariableList &variables) override;
+
+ void FindFunctions(const Module::LookupInfo &lookup_info,
+ const CompilerDeclContext &parent_decl_ctx,
+ bool include_inlines, SymbolContextList &sc_list) override;
+
+ void FindFunctions(const RegularExpression &regex, bool include_inlines,
+ SymbolContextList &sc_list) override;
+
+ void
+ GetMangledNamesForFunction(const std::string &scope_qualified_name,
+ std::vector<ConstString> &mangled_names) override;
+
+ uint64_t GetDebugInfoSize(bool load_all_debug_info = false) override;
+
+ void FindTypes(const lldb_private::TypeQuery &match,
+ lldb_private::TypeResults &results) override;
+
+ void GetTypes(SymbolContextScope *sc_scope, lldb::TypeClass type_mask,
+ TypeList &type_list) override;
+
+ llvm::Expected<lldb::TypeSystemSP>
+ GetTypeSystemForLanguage(lldb::LanguageType language) override;
+
+ CompilerDeclContext FindNamespace(ConstString name,
+ const CompilerDeclContext &parent_decl_ctx,
+ bool only_root_namespaces) override;
+
+ void PreloadSymbols() override;
+
+ std::recursive_mutex &GetModuleMutex() const override;
+
+ // PluginInterface protocol
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+ llvm::DWARFDebugAbbrev *DebugAbbrev();
+
+ DWARFDebugInfo &DebugInfo();
+
+ DWARFDebugRanges *GetDebugRanges();
+
+ static bool SupportedVersion(uint16_t version);
+
+ DWARFDIE
+ GetDeclContextDIEContainingDIE(const DWARFDIE &die);
+
+ bool HasForwardDeclForCompilerType(const CompilerType &compiler_type);
+
+ CompileUnit *GetCompUnitForDWARFCompUnit(DWARFCompileUnit &dwarf_cu);
+
+ virtual void GetObjCMethods(ConstString class_name,
+ llvm::function_ref<bool(DWARFDIE die)> callback);
+
+ bool Supports_DW_AT_APPLE_objc_complete_type(DWARFUnit *cu);
+
+ DebugMacrosSP ParseDebugMacros(lldb::offset_t *offset);
+
+ static DWARFDIE GetParentSymbolContextDIE(const DWARFDIE &die);
+
+ lldb::ModuleSP GetExternalModule(ConstString name);
+
+ typedef std::map<ConstString, lldb::ModuleSP> ExternalTypeModuleMap;
+
+ /// Return the list of Clang modules imported by this SymbolFile.
+ const ExternalTypeModuleMap &getExternalTypeModules() const {
+ return m_external_type_modules;
+ }
+
+ /// Given a DIERef, find the correct SymbolFileDWARF.
+ ///
+ /// A DIERef contains a file index that can uniquely identify a N_OSO file for
+ /// DWARF in .o files on mac, or a .dwo or .dwp file index for split DWARF.
+ /// Calling this function will find the correct symbol file to use so that
+ /// further lookups can be done on the correct symbol file so that the DIE
+ /// offset makes sense in the DIERef.
+ virtual SymbolFileDWARF *GetDIERefSymbolFile(const DIERef &die_ref);
+
+ virtual DWARFDIE GetDIE(const DIERef &die_ref);
+
+ DWARFDIE GetDIE(lldb::user_id_t uid);
+
+ std::shared_ptr<SymbolFileDWARFDwo>
+ GetDwoSymbolFileForCompileUnit(DWARFUnit &dwarf_cu,
+ const DWARFDebugInfoEntry &cu_die);
+
+ /// If this is a DWARF object with a single CU, return its DW_AT_dwo_id.
+ std::optional<uint64_t> GetDWOId();
+
+ /// Given a DWO DWARFUnit, find the corresponding skeleton DWARFUnit
+ /// in the main symbol file. DWP files can have their DWARFUnits
+ /// parsed without the skeleton compile units having been parsed, so
+ /// sometimes we need to find the skeleton compile unit for a DWO
+ /// DWARFUnit so we can fill in this link. Currently unless the
+ /// skeleton compile unit has been parsed _and_ the Unit DIE has been
+ /// parsed, the DWO unit will not have a backward link setup correctly
+ /// which was causing crashes due to an assertion that was firing
+ /// in SymbolFileDWARF::GetCompUnitForDWARFCompUnit().
+ DWARFUnit *GetSkeletonUnit(DWARFUnit *dwo_unit);
+
+ static bool DIEInDeclContext(const CompilerDeclContext &parent_decl_ctx,
+ const DWARFDIE &die,
+ bool only_root_namespaces = false);
+
+ std::vector<std::unique_ptr<CallEdge>>
+ ParseCallEdgesInFunction(UserID func_id) override;
+
+ void Dump(Stream &s) override;
+
+ void DumpClangAST(Stream &s) override;
+
+ /// List separate dwo files.
+ bool GetSeparateDebugInfo(StructuredData::Dictionary &d,
+ bool errors_only) override;
+
+ DWARFContext &GetDWARFContext() { return m_context; }
+
+ const std::shared_ptr<SymbolFileDWARFDwo> &GetDwpSymbolFile();
+
+ FileSpec GetFile(DWARFUnit &unit, size_t file_idx);
+
+ static llvm::Expected<lldb::TypeSystemSP> GetTypeSystem(DWARFUnit &unit);
+
+ static DWARFASTParser *GetDWARFParser(DWARFUnit &unit);
+
+ // CompilerDecl related functions
+
+ static CompilerDecl GetDecl(const DWARFDIE &die);
+
+ static CompilerDeclContext GetDeclContext(const DWARFDIE &die);
+
+ static CompilerDeclContext GetContainingDeclContext(const DWARFDIE &die);
+
+ static lldb::LanguageType LanguageTypeFromDWARF(uint64_t val);
+
+ static lldb::LanguageType GetLanguage(DWARFUnit &unit);
+ /// Same as GetLanguage() but reports all C++ versions as C++ (no version).
+ static lldb::LanguageType GetLanguageFamily(DWARFUnit &unit);
+
+ StatsDuration::Duration GetDebugInfoParseTime() override {
+ return m_parse_time;
+ }
+ StatsDuration::Duration GetDebugInfoIndexTime() override;
+
+ StatsDuration &GetDebugInfoParseTimeRef() { return m_parse_time; }
+
+ virtual lldb::offset_t
+ GetVendorDWARFOpcodeSize(const DataExtractor &data,
+ const lldb::offset_t data_offset,
+ const uint8_t op) const {
+ return LLDB_INVALID_OFFSET;
+ }
+
+ virtual bool ParseVendorDWARFOpcode(uint8_t op, const DataExtractor &opcodes,
+ lldb::offset_t &offset,
+ std::vector<Value> &stack) const {
+ return false;
+ }
+
+ ConstString ConstructFunctionDemangledName(const DWARFDIE &die);
+
+ std::optional<uint64_t> GetFileIndex() const { return m_file_index; }
+ void SetFileIndex(std::optional<uint64_t> file_index) {
+ m_file_index = file_index;
+ }
+
+ typedef llvm::DenseMap<const DWARFDebugInfoEntry *, Type *> DIEToTypePtr;
+
+ virtual DIEToTypePtr &GetDIEToType() { return m_die_to_type; }
+
+ virtual llvm::DenseMap<lldb::opaque_compiler_type_t, DIERef> &
+ GetForwardDeclCompilerTypeToDIE();
+
+ typedef llvm::DenseMap<const DWARFDebugInfoEntry *, lldb::VariableSP>
+ DIEToVariableSP;
+
+ virtual DIEToVariableSP &GetDIEToVariable() { return m_die_to_variable_sp; }
+
+ virtual UniqueDWARFASTTypeMap &GetUniqueDWARFASTTypeMap();
+
+ bool ClassOrStructIsVirtual(const DWARFDIE &die);
+
+ SymbolFileDWARFDebugMap *GetDebugMapSymfile();
+
+ virtual DWARFDIE FindDefinitionDIE(const DWARFDIE &die);
+
+ virtual lldb::TypeSP FindCompleteObjCDefinitionTypeForDIE(
+ const DWARFDIE &die, ConstString type_name, bool must_be_implementation);
+
+ Type *ResolveTypeUID(lldb::user_id_t type_uid) override;
+
+ Type *ResolveTypeUID(const DWARFDIE &die, bool assert_not_being_parsed);
+
+ Type *ResolveTypeUID(const DIERef &die_ref);
+
+ /// Returns the DWARFIndex for this symbol, if it exists.
+ DWARFIndex *getIndex() { return m_index.get(); }
+
+protected:
+ SymbolFileDWARF(const SymbolFileDWARF &) = delete;
+ const SymbolFileDWARF &operator=(const SymbolFileDWARF &) = delete;
+
+ virtual void LoadSectionData(lldb::SectionType sect_type,
+ DWARFDataExtractor &data);
+
+ bool DeclContextMatchesThisSymbolFile(const CompilerDeclContext &decl_ctx);
+
+ uint32_t CalculateNumCompileUnits() override;
+
+ lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index) override;
+
+ TypeList &GetTypeList() override;
+
+ lldb::CompUnitSP ParseCompileUnit(DWARFCompileUnit &dwarf_cu);
+
+ virtual DWARFCompileUnit *GetDWARFCompileUnit(CompileUnit *comp_unit);
+
+ DWARFUnit *GetNextUnparsedDWARFCompileUnit(DWARFUnit *prev_cu);
+
+ bool GetFunction(const DWARFDIE &die, SymbolContext &sc);
+
+ Function *ParseFunction(CompileUnit &comp_unit, const DWARFDIE &die);
+
+ size_t ParseBlocksRecursive(CompileUnit &comp_unit, Block *parent_block,
+ const DWARFDIE &die,
+ lldb::addr_t subprogram_low_pc, uint32_t depth);
+
+ size_t ParseTypes(const SymbolContext &sc, const DWARFDIE &die,
+ bool parse_siblings, bool parse_children);
+
+ lldb::TypeSP ParseType(const SymbolContext &sc, const DWARFDIE &die,
+ bool *type_is_new);
+
+ bool ParseSupportFiles(DWARFUnit &dwarf_cu, const lldb::ModuleSP &module,
+ SupportFileList &support_files);
+
+ lldb::VariableSP ParseVariableDIE(const SymbolContext &sc,
+ const DWARFDIE &die,
+ const lldb::addr_t func_low_pc);
+ lldb::VariableSP ParseVariableDIECached(const SymbolContext &sc,
+ const DWARFDIE &die);
+
+ void ParseAndAppendGlobalVariable(const SymbolContext &sc,
+ const DWARFDIE &die,
+ VariableList &cc_variable_list);
+
+ size_t ParseVariablesInFunctionContext(const SymbolContext &sc,
+ const DWARFDIE &die,
+ const lldb::addr_t func_low_pc);
+
+ size_t ParseVariablesInFunctionContextRecursive(const SymbolContext &sc,
+ const DWARFDIE &die,
+ lldb::addr_t func_low_pc,
+ DIEArray &accumulator);
+
+ size_t PopulateBlockVariableList(VariableList &variable_list,
+ const SymbolContext &sc,
+ llvm::ArrayRef<DIERef> variable_dies,
+ lldb::addr_t func_low_pc);
+
+ DIEArray MergeBlockAbstractParameters(const DWARFDIE &block_die,
+ DIEArray &&variable_dies);
+
+ // Given a die_offset, figure out the symbol context representing that die.
+ bool ResolveFunction(const DWARFDIE &die, bool include_inlines,
+ SymbolContextList &sc_list);
+
+ /// Resolve functions and (possibly) blocks for the given file address and a
+ /// compile unit. The compile unit comes from the sc argument and it must be
+ /// set. The results of the lookup (if any) are written back to the symbol
+ /// context.
+ void ResolveFunctionAndBlock(lldb::addr_t file_vm_addr, bool lookup_block,
+ SymbolContext &sc);
+
+ Symbol *GetObjCClassSymbol(ConstString objc_class_name);
+
+ lldb::TypeSP GetTypeForDIE(const DWARFDIE &die,
+ bool resolve_function_context = false);
+
+ void SetDebugMapModule(const lldb::ModuleSP &module_sp) {
+ m_debug_map_module_wp = module_sp;
+ }
+
+ DWARFDIE
+ FindBlockContainingSpecification(const DIERef &func_die_ref,
+ dw_offset_t spec_block_die_offset);
+
+ DWARFDIE
+ FindBlockContainingSpecification(const DWARFDIE &die,
+ dw_offset_t spec_block_die_offset);
+
+ bool ClassContainsSelector(const DWARFDIE &class_die, ConstString selector);
+
+ /// Parse call site entries (DW_TAG_call_site), including any nested call site
+ /// parameters (DW_TAG_call_site_parameter).
+ std::vector<std::unique_ptr<CallEdge>>
+ CollectCallEdges(lldb::ModuleSP module, DWARFDIE function_die);
+
+ /// If this symbol file is linked to by a debug map (see
+ /// SymbolFileDWARFDebugMap), and \p file_addr is a file address relative to
+ /// an object file, adjust \p file_addr so that it is relative to the main
+ /// binary. Returns the adjusted address, or \p file_addr if no adjustment is
+ /// needed, on success and LLDB_INVALID_ADDRESS otherwise.
+ lldb::addr_t FixupAddress(lldb::addr_t file_addr);
+
+ bool FixupAddress(Address &addr);
+
+ typedef llvm::SetVector<Type *> TypeSet;
+
+ void GetTypes(const DWARFDIE &die, dw_offset_t min_die_offset,
+ dw_offset_t max_die_offset, uint32_t type_mask,
+ TypeSet &type_set);
+
+ typedef RangeDataVector<lldb::addr_t, lldb::addr_t, Variable *>
+ GlobalVariableMap;
+
+ GlobalVariableMap &GetGlobalAranges();
+
+ void UpdateExternalModuleListIfNeeded();
+
+ void BuildCuTranslationTable();
+ std::optional<uint32_t> GetDWARFUnitIndex(uint32_t cu_idx);
+
+ void FindDwpSymbolFile();
+
+ const SupportFileList *GetTypeUnitSupportFiles(DWARFTypeUnit &tu);
+
+ void InitializeFirstCodeAddressRecursive(const SectionList &section_list);
+
+ void InitializeFirstCodeAddress();
+
+ void
+ GetCompileOptions(std::unordered_map<lldb::CompUnitSP, Args> &args) override;
+
+ lldb::ModuleWP m_debug_map_module_wp;
+ SymbolFileDWARFDebugMap *m_debug_map_symfile;
+
+ llvm::once_flag m_dwp_symfile_once_flag;
+ std::shared_ptr<SymbolFileDWARFDwo> m_dwp_symfile;
+
+ DWARFContext m_context;
+
+ llvm::once_flag m_info_once_flag;
+ std::unique_ptr<DWARFDebugInfo> m_info;
+
+ std::unique_ptr<llvm::DWARFDebugAbbrev> m_abbr;
+ std::unique_ptr<GlobalVariableMap> m_global_aranges_up;
+
+ typedef std::unordered_map<lldb::offset_t, DebugMacrosSP> DebugMacrosMap;
+ DebugMacrosMap m_debug_macros_map;
+
+ ExternalTypeModuleMap m_external_type_modules;
+ std::unique_ptr<DWARFIndex> m_index;
+ bool m_fetched_external_modules : 1;
+ LazyBool m_supports_DW_AT_APPLE_objc_complete_type;
+
+ typedef std::set<DIERef> DIERefSet;
+ typedef llvm::StringMap<DIERefSet> NameToOffsetMap;
+ NameToOffsetMap m_function_scope_qualified_name_map;
+ std::unique_ptr<DWARFDebugRanges> m_ranges;
+ UniqueDWARFASTTypeMap m_unique_ast_type_map;
+ // A map from DIE to lldb_private::Type. For record type, the key might be
+ // either declaration DIE or definition DIE.
+ DIEToTypePtr m_die_to_type;
+ DIEToVariableSP m_die_to_variable_sp;
+ // A map from CompilerType to the struct/class/union/enum DIE (might be a
+ // declaration or a definition) that is used to construct it.
+ llvm::DenseMap<lldb::opaque_compiler_type_t, DIERef>
+ m_forward_decl_compiler_type_to_die;
+ llvm::DenseMap<dw_offset_t, std::unique_ptr<SupportFileList>>
+ m_type_unit_support_files;
+ std::vector<uint32_t> m_lldb_cu_to_dwarf_unit;
+ /// DWARF does not provide a good way for traditional (concatenating) linkers
+ /// to invalidate debug info describing dead-stripped code. These linkers will
+ /// keep the debug info but resolve any addresses referring to such code as
+ /// zero (BFD) or a small positive integer (zero + relocation addend -- GOLD).
+ /// Try to filter out this debug info by comparing it to the lowest code
+ /// address in the module.
+ lldb::addr_t m_first_code_address = LLDB_INVALID_ADDRESS;
+ StatsDuration m_parse_time;
+ std::atomic_flag m_dwo_warning_issued = ATOMIC_FLAG_INIT;
+ /// If this DWARF file a .DWO file or a DWARF .o file on mac when
+ /// no dSYM file is being used, this file index will be set to a
+ /// valid value that can be used in DIERef objects which will contain
+ /// an index that identifies the .DWO or .o file.
+ std::optional<uint64_t> m_file_index;
+};
+} // namespace dwarf
+} // namespace lldb_private::plugin
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_SYMBOLFILEDWARF_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
new file mode 100644
index 000000000000..64cde16433ef
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
@@ -0,0 +1,1596 @@
+//===-- SymbolFileDWARFDebugMap.cpp ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolFileDWARFDebugMap.h"
+#include "DWARFCompileUnit.h"
+#include "DWARFDebugAranges.h"
+#include "DWARFDebugInfo.h"
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Utility/RangeMap.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/StructuredData.h"
+#include "lldb/Utility/Timer.h"
+
+//#define DEBUG_OSO_DMAP // DO NOT CHECKIN WITH THIS NOT COMMENTED OUT
+
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/LineTable.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Symbol/TypeMap.h"
+#include "lldb/Symbol/VariableList.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+#include "lldb/Target/StackFrame.h"
+
+#include "LogChannelDWARF.h"
+#include "SymbolFileDWARF.h"
+#include "lldb/lldb-private-enumerations.h"
+
+#include <memory>
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::plugin::dwarf;
+
+char SymbolFileDWARFDebugMap::ID;
+
+// Subclass lldb_private::Module so we can intercept the
+// "Module::GetObjectFile()" (so we can fixup the object file sections) and
+// also for "Module::GetSymbolFile()" (so we can fixup the symbol file id.
+
+const SymbolFileDWARFDebugMap::FileRangeMap &
+SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap(
+ SymbolFileDWARFDebugMap *exe_symfile) {
+ if (file_range_map_valid)
+ return file_range_map;
+
+ file_range_map_valid = true;
+
+ Module *oso_module = exe_symfile->GetModuleByCompUnitInfo(this);
+ if (!oso_module)
+ return file_range_map;
+
+ ObjectFile *oso_objfile = oso_module->GetObjectFile();
+ if (!oso_objfile)
+ return file_range_map;
+
+ Log *log = GetLog(DWARFLog::DebugMap);
+ LLDB_LOGF(
+ log,
+ "%p: SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap ('%s')",
+ static_cast<void *>(this),
+ oso_module->GetSpecificationDescription().c_str());
+
+ std::vector<SymbolFileDWARFDebugMap::CompileUnitInfo *> cu_infos;
+ if (exe_symfile->GetCompUnitInfosForModule(oso_module, cu_infos)) {
+ for (auto comp_unit_info : cu_infos) {
+ Symtab *exe_symtab = exe_symfile->GetObjectFile()->GetSymtab();
+ ModuleSP oso_module_sp(oso_objfile->GetModule());
+ Symtab *oso_symtab = oso_objfile->GetSymtab();
+
+ /// const uint32_t fun_resolve_flags = SymbolContext::Module |
+ /// eSymbolContextCompUnit | eSymbolContextFunction;
+ // SectionList *oso_sections = oso_objfile->Sections();
+ // Now we need to make sections that map from zero based object file
+ // addresses to where things ended up in the main executable.
+
+ assert(comp_unit_info->first_symbol_index != UINT32_MAX);
+ // End index is one past the last valid symbol index
+ const uint32_t oso_end_idx = comp_unit_info->last_symbol_index + 1;
+ for (uint32_t idx = comp_unit_info->first_symbol_index +
+ 2; // Skip the N_SO and N_OSO
+ idx < oso_end_idx; ++idx) {
+ Symbol *exe_symbol = exe_symtab->SymbolAtIndex(idx);
+ if (exe_symbol) {
+ if (!exe_symbol->IsDebug())
+ continue;
+
+ switch (exe_symbol->GetType()) {
+ default:
+ break;
+
+ case eSymbolTypeCode: {
+ // For each N_FUN, or function that we run into in the debug map we
+ // make a new section that we add to the sections found in the .o
+ // file. This new section has the file address set to what the
+ // addresses are in the .o file, and the load address is adjusted
+ // to match where it ended up in the final executable! We do this
+ // before we parse any dwarf info so that when it goes get parsed
+ // all section/offset addresses that get registered will resolve
+ // correctly to the new addresses in the main executable.
+
+ // First we find the original symbol in the .o file's symbol table
+ Symbol *oso_fun_symbol = oso_symtab->FindFirstSymbolWithNameAndType(
+ exe_symbol->GetMangled().GetName(Mangled::ePreferMangled),
+ eSymbolTypeCode, Symtab::eDebugNo, Symtab::eVisibilityAny);
+ if (oso_fun_symbol) {
+ // Add the inverse OSO file address to debug map entry mapping
+ exe_symfile->AddOSOFileRange(
+ this, exe_symbol->GetAddressRef().GetFileAddress(),
+ exe_symbol->GetByteSize(),
+ oso_fun_symbol->GetAddressRef().GetFileAddress(),
+ oso_fun_symbol->GetByteSize());
+ }
+ } break;
+
+ case eSymbolTypeData: {
+ // For each N_GSYM we remap the address for the global by making a
+ // new section that we add to the sections found in the .o file.
+ // This new section has the file address set to what the addresses
+ // are in the .o file, and the load address is adjusted to match
+ // where it ended up in the final executable! We do this before we
+ // parse any dwarf info so that when it goes get parsed all
+ // section/offset addresses that get registered will resolve
+ // correctly to the new addresses in the main executable. We
+ // initially set the section size to be 1 byte, but will need to
+ // fix up these addresses further after all globals have been
+ // parsed to span the gaps, or we can find the global variable
+ // sizes from the DWARF info as we are parsing.
+
+ // Next we find the non-stab entry that corresponds to the N_GSYM
+ // in the .o file
+ Symbol *oso_gsym_symbol =
+ oso_symtab->FindFirstSymbolWithNameAndType(
+ exe_symbol->GetMangled().GetName(Mangled::ePreferMangled),
+ eSymbolTypeData, Symtab::eDebugNo, Symtab::eVisibilityAny);
+ if (exe_symbol && oso_gsym_symbol && exe_symbol->ValueIsAddress() &&
+ oso_gsym_symbol->ValueIsAddress()) {
+ // Add the inverse OSO file address to debug map entry mapping
+ exe_symfile->AddOSOFileRange(
+ this, exe_symbol->GetAddressRef().GetFileAddress(),
+ exe_symbol->GetByteSize(),
+ oso_gsym_symbol->GetAddressRef().GetFileAddress(),
+ oso_gsym_symbol->GetByteSize());
+ }
+ } break;
+ }
+ }
+ }
+
+ exe_symfile->FinalizeOSOFileRanges(this);
+ // We don't need the symbols anymore for the .o files
+ oso_objfile->ClearSymtab();
+ }
+ }
+ return file_range_map;
+}
+
+namespace lldb_private::plugin {
+namespace dwarf {
+class DebugMapModule : public Module {
+public:
+ DebugMapModule(const ModuleSP &exe_module_sp, uint32_t cu_idx,
+ const FileSpec &file_spec, const ArchSpec &arch,
+ ConstString object_name, off_t object_offset,
+ const llvm::sys::TimePoint<> object_mod_time)
+ : Module(file_spec, arch, object_name, object_offset, object_mod_time),
+ m_exe_module_wp(exe_module_sp), m_cu_idx(cu_idx) {}
+
+ ~DebugMapModule() override = default;
+
+ SymbolFile *
+ GetSymbolFile(bool can_create = true,
+ lldb_private::Stream *feedback_strm = nullptr) override {
+ // Scope for locker
+ if (m_symfile_up.get() || !can_create)
+ return m_symfile_up ? m_symfile_up->GetSymbolFile() : nullptr;
+
+ ModuleSP exe_module_sp(m_exe_module_wp.lock());
+ if (exe_module_sp) {
+ // Now get the object file outside of a locking scope
+ ObjectFile *oso_objfile = GetObjectFile();
+ if (oso_objfile) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ if (SymbolFile *symfile =
+ Module::GetSymbolFile(can_create, feedback_strm)) {
+ // Set a pointer to this class to set our OSO DWARF file know that
+ // the DWARF is being used along with a debug map and that it will
+ // have the remapped sections that we do below.
+ SymbolFileDWARF *oso_symfile =
+ SymbolFileDWARFDebugMap::GetSymbolFileAsSymbolFileDWARF(symfile);
+
+ if (!oso_symfile)
+ return nullptr;
+
+ ObjectFile *exe_objfile = exe_module_sp->GetObjectFile();
+ SymbolFile *exe_symfile = exe_module_sp->GetSymbolFile();
+
+ if (exe_objfile && exe_symfile) {
+ oso_symfile->SetDebugMapModule(exe_module_sp);
+ // Set the ID of the symbol file DWARF to the index of the OSO
+ // shifted left by 32 bits to provide a unique prefix for any
+ // UserID's that get created in the symbol file.
+ oso_symfile->SetFileIndex((uint64_t)m_cu_idx);
+ }
+ return symfile;
+ }
+ }
+ }
+ return nullptr;
+ }
+
+protected:
+ ModuleWP m_exe_module_wp;
+ const uint32_t m_cu_idx;
+};
+} // namespace dwarf
+} // namespace lldb_private::plugin
+
+void SymbolFileDWARFDebugMap::Initialize() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(), CreateInstance);
+}
+
+void SymbolFileDWARFDebugMap::Terminate() {
+ PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+llvm::StringRef SymbolFileDWARFDebugMap::GetPluginDescriptionStatic() {
+ return "DWARF and DWARF3 debug symbol file reader (debug map).";
+}
+
+SymbolFile *SymbolFileDWARFDebugMap::CreateInstance(ObjectFileSP objfile_sp) {
+ return new SymbolFileDWARFDebugMap(std::move(objfile_sp));
+}
+
+SymbolFileDWARFDebugMap::SymbolFileDWARFDebugMap(ObjectFileSP objfile_sp)
+ : SymbolFileCommon(std::move(objfile_sp)), m_flags(), m_compile_unit_infos(),
+ m_func_indexes(), m_glob_indexes(),
+ m_supports_DW_AT_APPLE_objc_complete_type(eLazyBoolCalculate) {}
+
+SymbolFileDWARFDebugMap::~SymbolFileDWARFDebugMap() = default;
+
+void SymbolFileDWARFDebugMap::InitializeObject() {}
+
+void SymbolFileDWARFDebugMap::InitOSO() {
+ if (m_flags.test(kHaveInitializedOSOs))
+ return;
+
+ m_flags.set(kHaveInitializedOSOs);
+
+ // If the object file has been stripped, there is no sense in looking further
+ // as all of the debug symbols for the debug map will not be available
+ if (m_objfile_sp->IsStripped())
+ return;
+
+ // Also make sure the file type is some sort of executable. Core files, debug
+ // info files (dSYM), object files (.o files), and stub libraries all can
+ switch (m_objfile_sp->GetType()) {
+ case ObjectFile::eTypeInvalid:
+ case ObjectFile::eTypeCoreFile:
+ case ObjectFile::eTypeDebugInfo:
+ case ObjectFile::eTypeObjectFile:
+ case ObjectFile::eTypeStubLibrary:
+ case ObjectFile::eTypeUnknown:
+ case ObjectFile::eTypeJIT:
+ return;
+
+ case ObjectFile::eTypeExecutable:
+ case ObjectFile::eTypeDynamicLinker:
+ case ObjectFile::eTypeSharedLibrary:
+ break;
+ }
+
+ // In order to get the abilities of this plug-in, we look at the list of
+ // N_OSO entries (object files) from the symbol table and make sure that
+ // these files exist and also contain valid DWARF. If we get any of that then
+ // we return the abilities of the first N_OSO's DWARF.
+
+ Symtab *symtab = m_objfile_sp->GetSymtab();
+ if (!symtab)
+ return;
+
+ Log *log = GetLog(DWARFLog::DebugMap);
+
+ std::vector<uint32_t> oso_indexes;
+ // When a mach-o symbol is encoded, the n_type field is encoded in bits
+ // 23:16, and the n_desc field is encoded in bits 15:0.
+ //
+ // To find all N_OSO entries that are part of the DWARF + debug map we find
+ // only object file symbols with the flags value as follows: bits 23:16 ==
+ // 0x66 (N_OSO) bits 15: 0 == 0x0001 (specifies this is a debug map object
+ // file)
+ const uint32_t k_oso_symbol_flags_value = 0x660001u;
+
+ const uint32_t oso_index_count =
+ symtab->AppendSymbolIndexesWithTypeAndFlagsValue(
+ eSymbolTypeObjectFile, k_oso_symbol_flags_value, oso_indexes);
+
+ if (oso_index_count == 0)
+ return;
+
+ symtab->AppendSymbolIndexesWithType(eSymbolTypeCode, Symtab::eDebugYes,
+ Symtab::eVisibilityAny, m_func_indexes);
+ symtab->AppendSymbolIndexesWithType(eSymbolTypeData, Symtab::eDebugYes,
+ Symtab::eVisibilityAny, m_glob_indexes);
+
+ symtab->SortSymbolIndexesByValue(m_func_indexes, true);
+ symtab->SortSymbolIndexesByValue(m_glob_indexes, true);
+
+ for (uint32_t sym_idx :
+ llvm::concat<uint32_t>(m_func_indexes, m_glob_indexes)) {
+ const Symbol *symbol = symtab->SymbolAtIndex(sym_idx);
+ lldb::addr_t file_addr = symbol->GetAddressRef().GetFileAddress();
+ lldb::addr_t byte_size = symbol->GetByteSize();
+ DebugMap::Entry debug_map_entry(file_addr, byte_size,
+ OSOEntry(sym_idx, LLDB_INVALID_ADDRESS));
+ m_debug_map.Append(debug_map_entry);
+ }
+ m_debug_map.Sort();
+
+ m_compile_unit_infos.resize(oso_index_count);
+
+ for (uint32_t i = 0; i < oso_index_count; ++i) {
+ const uint32_t so_idx = oso_indexes[i] - 1;
+ const uint32_t oso_idx = oso_indexes[i];
+ const Symbol *so_symbol = symtab->SymbolAtIndex(so_idx);
+ const Symbol *oso_symbol = symtab->SymbolAtIndex(oso_idx);
+ if (so_symbol && oso_symbol &&
+ so_symbol->GetType() == eSymbolTypeSourceFile &&
+ oso_symbol->GetType() == eSymbolTypeObjectFile) {
+ m_compile_unit_infos[i].so_file.SetFile(so_symbol->GetName().AsCString(),
+ FileSpec::Style::native);
+ m_compile_unit_infos[i].oso_path = oso_symbol->GetName();
+ m_compile_unit_infos[i].oso_mod_time =
+ llvm::sys::toTimePoint(oso_symbol->GetIntegerValue(0));
+ uint32_t sibling_idx = so_symbol->GetSiblingIndex();
+ // The sibling index can't be less that or equal to the current index
+ // "i"
+ if (sibling_idx <= i || sibling_idx == UINT32_MAX) {
+ m_objfile_sp->GetModule()->ReportError(
+ "N_SO in symbol with UID {0} has invalid sibling in debug "
+ "map, "
+ "please file a bug and attach the binary listed in this error",
+ so_symbol->GetID());
+ } else {
+ const Symbol *last_symbol = symtab->SymbolAtIndex(sibling_idx - 1);
+ m_compile_unit_infos[i].first_symbol_index = so_idx;
+ m_compile_unit_infos[i].last_symbol_index = sibling_idx - 1;
+ m_compile_unit_infos[i].first_symbol_id = so_symbol->GetID();
+ m_compile_unit_infos[i].last_symbol_id = last_symbol->GetID();
+
+ LLDB_LOGF(log, "Initialized OSO 0x%8.8x: file=%s", i,
+ oso_symbol->GetName().GetCString());
+ }
+ } else {
+ if (oso_symbol == nullptr)
+ m_objfile_sp->GetModule()->ReportError(
+ "N_OSO symbol[{0}] can't be found, please file a bug and "
+ "attach "
+ "the binary listed in this error",
+ oso_idx);
+ else if (so_symbol == nullptr)
+ m_objfile_sp->GetModule()->ReportError(
+ "N_SO not found for N_OSO symbol[{0}], please file a bug and "
+ "attach the binary listed in this error",
+ oso_idx);
+ else if (so_symbol->GetType() != eSymbolTypeSourceFile)
+ m_objfile_sp->GetModule()->ReportError(
+ "N_SO has incorrect symbol type ({0}) for N_OSO "
+ "symbol[{1}], "
+ "please file a bug and attach the binary listed in this error",
+ so_symbol->GetType(), oso_idx);
+ else if (oso_symbol->GetType() != eSymbolTypeSourceFile)
+ m_objfile_sp->GetModule()->ReportError(
+ "N_OSO has incorrect symbol type ({0}) for N_OSO "
+ "symbol[{1}], "
+ "please file a bug and attach the binary listed in this error",
+ oso_symbol->GetType(), oso_idx);
+ }
+ }
+}
+
+Module *SymbolFileDWARFDebugMap::GetModuleByOSOIndex(uint32_t oso_idx) {
+ const uint32_t cu_count = GetNumCompileUnits();
+ if (oso_idx < cu_count)
+ return GetModuleByCompUnitInfo(&m_compile_unit_infos[oso_idx]);
+ return nullptr;
+}
+
+Module *SymbolFileDWARFDebugMap::GetModuleByCompUnitInfo(
+ CompileUnitInfo *comp_unit_info) {
+ if (!comp_unit_info->oso_sp) {
+ auto pos = m_oso_map.find(
+ {comp_unit_info->oso_path, comp_unit_info->oso_mod_time});
+ if (pos != m_oso_map.end()) {
+ comp_unit_info->oso_sp = pos->second;
+ } else {
+ ObjectFile *obj_file = GetObjectFile();
+ comp_unit_info->oso_sp = std::make_shared<OSOInfo>();
+ m_oso_map[{comp_unit_info->oso_path, comp_unit_info->oso_mod_time}] =
+ comp_unit_info->oso_sp;
+ const char *oso_path = comp_unit_info->oso_path.GetCString();
+ FileSpec oso_file(oso_path);
+ ConstString oso_object;
+ if (FileSystem::Instance().Exists(oso_file)) {
+ // The modification time returned by the FS can have a higher precision
+ // than the one from the CU.
+ auto oso_mod_time = std::chrono::time_point_cast<std::chrono::seconds>(
+ FileSystem::Instance().GetModificationTime(oso_file));
+ // A timestamp of 0 means that the linker was in deterministic mode. In
+ // that case, we should skip the check against the filesystem last
+ // modification timestamp, since it will never match.
+ if (comp_unit_info->oso_mod_time != llvm::sys::TimePoint<>() &&
+ oso_mod_time != comp_unit_info->oso_mod_time) {
+ comp_unit_info->oso_load_error.SetErrorStringWithFormat(
+ "debug map object file \"%s\" changed (actual: 0x%8.8x, debug "
+ "map: 0x%8.8x) since this executable was linked, debug info "
+ "will not be loaded", oso_file.GetPath().c_str(),
+ (uint32_t)llvm::sys::toTimeT(oso_mod_time),
+ (uint32_t)llvm::sys::toTimeT(comp_unit_info->oso_mod_time));
+ obj_file->GetModule()->ReportError(
+ "{0}", comp_unit_info->oso_load_error.AsCString());
+ return nullptr;
+ }
+
+ } else {
+ const bool must_exist = true;
+
+ if (!ObjectFile::SplitArchivePathWithObject(oso_path, oso_file,
+ oso_object, must_exist)) {
+ comp_unit_info->oso_load_error.SetErrorStringWithFormat(
+ "debug map object file \"%s\" containing debug info does not "
+ "exist, debug info will not be loaded",
+ comp_unit_info->oso_path.GetCString());
+ return nullptr;
+ }
+ }
+ // Always create a new module for .o files. Why? Because we use the debug
+ // map, to add new sections to each .o file and even though a .o file
+ // might not have changed, the sections that get added to the .o file can
+ // change.
+ ArchSpec oso_arch;
+ // Only adopt the architecture from the module (not the vendor or OS)
+ // since .o files for "i386-apple-ios" will historically show up as "i386
+ // -apple-macosx" due to the lack of a LC_VERSION_MIN_MACOSX or
+ // LC_VERSION_MIN_IPHONEOS load command...
+ oso_arch.SetTriple(m_objfile_sp->GetModule()
+ ->GetArchitecture()
+ .GetTriple()
+ .getArchName()
+ .str()
+ .c_str());
+ comp_unit_info->oso_sp->module_sp = std::make_shared<DebugMapModule>(
+ obj_file->GetModule(), GetCompUnitInfoIndex(comp_unit_info), oso_file,
+ oso_arch, oso_object, 0,
+ oso_object ? comp_unit_info->oso_mod_time : llvm::sys::TimePoint<>());
+
+ if (oso_object && !comp_unit_info->oso_sp->module_sp->GetObjectFile() &&
+ FileSystem::Instance().Exists(oso_file)) {
+ // If we are loading a .o file from a .a file the "oso_object" will
+ // have a valid value name and if the .a file exists, either the .o
+ // file didn't exist in the .a file or the mod time didn't match.
+ comp_unit_info->oso_load_error.SetErrorStringWithFormat(
+ "\"%s\" object from the \"%s\" archive: "
+ "either the .o file doesn't exist in the archive or the "
+ "modification time (0x%8.8x) of the .o file doesn't match",
+ oso_object.AsCString(), oso_file.GetPath().c_str(),
+ (uint32_t)llvm::sys::toTimeT(comp_unit_info->oso_mod_time));
+ }
+ }
+ }
+ if (comp_unit_info->oso_sp)
+ return comp_unit_info->oso_sp->module_sp.get();
+ return nullptr;
+}
+
+bool SymbolFileDWARFDebugMap::GetFileSpecForSO(uint32_t oso_idx,
+ FileSpec &file_spec) {
+ if (oso_idx < m_compile_unit_infos.size()) {
+ if (m_compile_unit_infos[oso_idx].so_file) {
+ file_spec = m_compile_unit_infos[oso_idx].so_file;
+ return true;
+ }
+ }
+ return false;
+}
+
+ObjectFile *SymbolFileDWARFDebugMap::GetObjectFileByOSOIndex(uint32_t oso_idx) {
+ Module *oso_module = GetModuleByOSOIndex(oso_idx);
+ if (oso_module)
+ return oso_module->GetObjectFile();
+ return nullptr;
+}
+
+SymbolFileDWARF *
+SymbolFileDWARFDebugMap::GetSymbolFile(const SymbolContext &sc) {
+ return GetSymbolFile(*sc.comp_unit);
+}
+
+SymbolFileDWARF *
+SymbolFileDWARFDebugMap::GetSymbolFile(const CompileUnit &comp_unit) {
+ CompileUnitInfo *comp_unit_info = GetCompUnitInfo(comp_unit);
+ if (comp_unit_info)
+ return GetSymbolFileByCompUnitInfo(comp_unit_info);
+ return nullptr;
+}
+
+ObjectFile *SymbolFileDWARFDebugMap::GetObjectFileByCompUnitInfo(
+ CompileUnitInfo *comp_unit_info) {
+ Module *oso_module = GetModuleByCompUnitInfo(comp_unit_info);
+ if (oso_module)
+ return oso_module->GetObjectFile();
+ return nullptr;
+}
+
+uint32_t SymbolFileDWARFDebugMap::GetCompUnitInfoIndex(
+ const CompileUnitInfo *comp_unit_info) {
+ if (!m_compile_unit_infos.empty()) {
+ const CompileUnitInfo *first_comp_unit_info = &m_compile_unit_infos.front();
+ const CompileUnitInfo *last_comp_unit_info = &m_compile_unit_infos.back();
+ if (first_comp_unit_info <= comp_unit_info &&
+ comp_unit_info <= last_comp_unit_info)
+ return comp_unit_info - first_comp_unit_info;
+ }
+ return UINT32_MAX;
+}
+
+SymbolFileDWARF *
+SymbolFileDWARFDebugMap::GetSymbolFileByOSOIndex(uint32_t oso_idx) {
+ unsigned size = m_compile_unit_infos.size();
+ if (oso_idx < size)
+ return GetSymbolFileByCompUnitInfo(&m_compile_unit_infos[oso_idx]);
+ return nullptr;
+}
+
+SymbolFileDWARF *
+SymbolFileDWARFDebugMap::GetSymbolFileAsSymbolFileDWARF(SymbolFile *sym_file) {
+ if (sym_file &&
+ sym_file->GetPluginName() == SymbolFileDWARF::GetPluginNameStatic())
+ return static_cast<SymbolFileDWARF *>(sym_file);
+ return nullptr;
+}
+
+SymbolFileDWARF *SymbolFileDWARFDebugMap::GetSymbolFileByCompUnitInfo(
+ CompileUnitInfo *comp_unit_info) {
+ if (Module *oso_module = GetModuleByCompUnitInfo(comp_unit_info))
+ return GetSymbolFileAsSymbolFileDWARF(oso_module->GetSymbolFile());
+ return nullptr;
+}
+
+uint32_t SymbolFileDWARFDebugMap::CalculateAbilities() {
+ // In order to get the abilities of this plug-in, we look at the list of
+ // N_OSO entries (object files) from the symbol table and make sure that
+ // these files exist and also contain valid DWARF. If we get any of that then
+ // we return the abilities of the first N_OSO's DWARF.
+
+ const uint32_t oso_index_count = GetNumCompileUnits();
+ if (oso_index_count > 0) {
+ InitOSO();
+ if (!m_compile_unit_infos.empty()) {
+ return SymbolFile::CompileUnits | SymbolFile::Functions |
+ SymbolFile::Blocks | SymbolFile::GlobalVariables |
+ SymbolFile::LocalVariables | SymbolFile::VariableTypes |
+ SymbolFile::LineTables;
+ }
+ }
+ return 0;
+}
+
+uint32_t SymbolFileDWARFDebugMap::CalculateNumCompileUnits() {
+ InitOSO();
+ return m_compile_unit_infos.size();
+}
+
+CompUnitSP SymbolFileDWARFDebugMap::ParseCompileUnitAtIndex(uint32_t cu_idx) {
+ CompUnitSP comp_unit_sp;
+ const uint32_t cu_count = GetNumCompileUnits();
+
+ if (cu_idx < cu_count) {
+ auto &cu_info = m_compile_unit_infos[cu_idx];
+ Module *oso_module = GetModuleByCompUnitInfo(&cu_info);
+ if (oso_module) {
+ FileSpec so_file_spec;
+ if (GetFileSpecForSO(cu_idx, so_file_spec)) {
+ // User zero as the ID to match the compile unit at offset zero in each
+ // .o file.
+ lldb::user_id_t cu_id = 0;
+ cu_info.compile_units_sps.push_back(std::make_shared<CompileUnit>(
+ m_objfile_sp->GetModule(), nullptr,
+ std::make_shared<SupportFile>(so_file_spec), cu_id,
+ eLanguageTypeUnknown, eLazyBoolCalculate));
+ cu_info.id_to_index_map.insert({0, 0});
+ SetCompileUnitAtIndex(cu_idx, cu_info.compile_units_sps[0]);
+ // If there's a symbol file also register all the extra compile units.
+ if (SymbolFileDWARF *oso_symfile =
+ GetSymbolFileByCompUnitInfo(&cu_info)) {
+ auto num_dwarf_units = oso_symfile->DebugInfo().GetNumUnits();
+ for (size_t i = 0; i < num_dwarf_units; ++i) {
+ auto *dwarf_unit = oso_symfile->DebugInfo().GetUnitAtIndex(i);
+ if (auto *dwarf_cu = llvm::dyn_cast<DWARFCompileUnit>(dwarf_unit)) {
+ // The "main" one was already registered.
+ if (dwarf_cu->GetID() == 0)
+ continue;
+ cu_info.compile_units_sps.push_back(std::make_shared<CompileUnit>(
+ m_objfile_sp->GetModule(), nullptr,
+ std::make_shared<SupportFile>(so_file_spec),
+ dwarf_cu->GetID(), eLanguageTypeUnknown, eLazyBoolCalculate));
+ cu_info.id_to_index_map.insert(
+ {dwarf_cu->GetID(), cu_info.compile_units_sps.size() - 1});
+ }
+ }
+ }
+ }
+ }
+ if (!cu_info.compile_units_sps.empty())
+ comp_unit_sp = cu_info.compile_units_sps[0];
+ }
+
+ return comp_unit_sp;
+}
+
+SymbolFileDWARFDebugMap::CompileUnitInfo *
+SymbolFileDWARFDebugMap::GetCompUnitInfo(const SymbolContext &sc) {
+ return GetCompUnitInfo(*sc.comp_unit);
+}
+
+SymbolFileDWARFDebugMap::CompileUnitInfo *
+SymbolFileDWARFDebugMap::GetCompUnitInfo(const CompileUnit &comp_unit) {
+ const uint32_t cu_count = GetNumCompileUnits();
+ for (uint32_t i = 0; i < cu_count; ++i) {
+ auto &id_to_index_map = m_compile_unit_infos[i].id_to_index_map;
+
+ auto it = id_to_index_map.find(comp_unit.GetID());
+ if (it != id_to_index_map.end() &&
+ &comp_unit ==
+ m_compile_unit_infos[i].compile_units_sps[it->getSecond()].get())
+ return &m_compile_unit_infos[i];
+ }
+ return nullptr;
+}
+
+size_t SymbolFileDWARFDebugMap::GetCompUnitInfosForModule(
+ const lldb_private::Module *module,
+ std::vector<CompileUnitInfo *> &cu_infos) {
+ const uint32_t cu_count = GetNumCompileUnits();
+ for (uint32_t i = 0; i < cu_count; ++i) {
+ if (module == GetModuleByCompUnitInfo(&m_compile_unit_infos[i]))
+ cu_infos.push_back(&m_compile_unit_infos[i]);
+ }
+ return cu_infos.size();
+}
+
+lldb::LanguageType
+SymbolFileDWARFDebugMap::ParseLanguage(CompileUnit &comp_unit) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ SymbolFileDWARF *oso_dwarf = GetSymbolFile(comp_unit);
+ if (oso_dwarf)
+ return oso_dwarf->ParseLanguage(comp_unit);
+ return eLanguageTypeUnknown;
+}
+
+XcodeSDK SymbolFileDWARFDebugMap::ParseXcodeSDK(CompileUnit &comp_unit) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ SymbolFileDWARF *oso_dwarf = GetSymbolFile(comp_unit);
+ if (oso_dwarf)
+ return oso_dwarf->ParseXcodeSDK(comp_unit);
+ return {};
+}
+
+llvm::SmallSet<lldb::LanguageType, 4>
+SymbolFileDWARFDebugMap::ParseAllLanguages(
+ lldb_private::CompileUnit &comp_unit) {
+ llvm::SmallSet<lldb::LanguageType, 4> langs;
+ auto *info = GetCompUnitInfo(comp_unit);
+ for (auto &comp_unit : info->compile_units_sps) {
+ langs.insert(comp_unit->GetLanguage());
+ }
+ return langs;
+}
+
+size_t SymbolFileDWARFDebugMap::ParseFunctions(CompileUnit &comp_unit) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ SymbolFileDWARF *oso_dwarf = GetSymbolFile(comp_unit);
+ if (oso_dwarf)
+ return oso_dwarf->ParseFunctions(comp_unit);
+ return 0;
+}
+
+bool SymbolFileDWARFDebugMap::ParseLineTable(CompileUnit &comp_unit) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ SymbolFileDWARF *oso_dwarf = GetSymbolFile(comp_unit);
+ if (oso_dwarf)
+ return oso_dwarf->ParseLineTable(comp_unit);
+ return false;
+}
+
+bool SymbolFileDWARFDebugMap::ParseDebugMacros(CompileUnit &comp_unit) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ SymbolFileDWARF *oso_dwarf = GetSymbolFile(comp_unit);
+ if (oso_dwarf)
+ return oso_dwarf->ParseDebugMacros(comp_unit);
+ return false;
+}
+
+bool SymbolFileDWARFDebugMap::ForEachExternalModule(
+ CompileUnit &comp_unit,
+ llvm::DenseSet<lldb_private::SymbolFile *> &visited_symbol_files,
+ llvm::function_ref<bool(Module &)> f) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ SymbolFileDWARF *oso_dwarf = GetSymbolFile(comp_unit);
+ if (oso_dwarf)
+ return oso_dwarf->ForEachExternalModule(comp_unit, visited_symbol_files, f);
+ return false;
+}
+
+bool SymbolFileDWARFDebugMap::ParseSupportFiles(
+ CompileUnit &comp_unit, SupportFileList &support_files) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ SymbolFileDWARF *oso_dwarf = GetSymbolFile(comp_unit);
+ if (oso_dwarf)
+ return oso_dwarf->ParseSupportFiles(comp_unit, support_files);
+ return false;
+}
+
+bool SymbolFileDWARFDebugMap::ParseIsOptimized(CompileUnit &comp_unit) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ SymbolFileDWARF *oso_dwarf = GetSymbolFile(comp_unit);
+ if (oso_dwarf)
+ return oso_dwarf->ParseIsOptimized(comp_unit);
+ return false;
+}
+
+bool SymbolFileDWARFDebugMap::ParseImportedModules(
+ const SymbolContext &sc, std::vector<SourceModule> &imported_modules) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ SymbolFileDWARF *oso_dwarf = GetSymbolFile(sc);
+ if (oso_dwarf)
+ return oso_dwarf->ParseImportedModules(sc, imported_modules);
+ return false;
+}
+
+size_t SymbolFileDWARFDebugMap::ParseBlocksRecursive(Function &func) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ CompileUnit *comp_unit = func.GetCompileUnit();
+ if (!comp_unit)
+ return 0;
+
+ SymbolFileDWARF *oso_dwarf = GetSymbolFile(*comp_unit);
+ if (oso_dwarf)
+ return oso_dwarf->ParseBlocksRecursive(func);
+ return 0;
+}
+
+size_t SymbolFileDWARFDebugMap::ParseTypes(CompileUnit &comp_unit) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ SymbolFileDWARF *oso_dwarf = GetSymbolFile(comp_unit);
+ if (oso_dwarf)
+ return oso_dwarf->ParseTypes(comp_unit);
+ return 0;
+}
+
+size_t
+SymbolFileDWARFDebugMap::ParseVariablesForContext(const SymbolContext &sc) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ SymbolFileDWARF *oso_dwarf = GetSymbolFile(sc);
+ if (oso_dwarf)
+ return oso_dwarf->ParseVariablesForContext(sc);
+ return 0;
+}
+
+Type *SymbolFileDWARFDebugMap::ResolveTypeUID(lldb::user_id_t type_uid) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ const uint64_t oso_idx = GetOSOIndexFromUserID(type_uid);
+ SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex(oso_idx);
+ if (oso_dwarf)
+ return oso_dwarf->ResolveTypeUID(type_uid);
+ return nullptr;
+}
+
+std::optional<SymbolFile::ArrayInfo>
+SymbolFileDWARFDebugMap::GetDynamicArrayInfoForUID(
+ lldb::user_id_t type_uid, const lldb_private::ExecutionContext *exe_ctx) {
+ const uint64_t oso_idx = GetOSOIndexFromUserID(type_uid);
+ SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex(oso_idx);
+ if (oso_dwarf)
+ return oso_dwarf->GetDynamicArrayInfoForUID(type_uid, exe_ctx);
+ return std::nullopt;
+}
+
+bool SymbolFileDWARFDebugMap::CompleteType(CompilerType &compiler_type) {
+ bool success = false;
+ if (compiler_type) {
+ ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) {
+ if (oso_dwarf->HasForwardDeclForCompilerType(compiler_type)) {
+ oso_dwarf->CompleteType(compiler_type);
+ success = true;
+ return IterationAction::Stop;
+ }
+ return IterationAction::Continue;
+ });
+ }
+ return success;
+}
+
+uint32_t
+SymbolFileDWARFDebugMap::ResolveSymbolContext(const Address &exe_so_addr,
+ SymbolContextItem resolve_scope,
+ SymbolContext &sc) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ uint32_t resolved_flags = 0;
+ Symtab *symtab = m_objfile_sp->GetSymtab();
+ if (symtab) {
+ const addr_t exe_file_addr = exe_so_addr.GetFileAddress();
+
+ const DebugMap::Entry *debug_map_entry =
+ m_debug_map.FindEntryThatContains(exe_file_addr);
+ if (debug_map_entry) {
+
+ sc.symbol =
+ symtab->SymbolAtIndex(debug_map_entry->data.GetExeSymbolIndex());
+
+ if (sc.symbol != nullptr) {
+ resolved_flags |= eSymbolContextSymbol;
+
+ uint32_t oso_idx = 0;
+ CompileUnitInfo *comp_unit_info =
+ GetCompileUnitInfoForSymbolWithID(sc.symbol->GetID(), &oso_idx);
+ if (comp_unit_info) {
+ comp_unit_info->GetFileRangeMap(this);
+ Module *oso_module = GetModuleByCompUnitInfo(comp_unit_info);
+ if (oso_module) {
+ lldb::addr_t oso_file_addr =
+ exe_file_addr - debug_map_entry->GetRangeBase() +
+ debug_map_entry->data.GetOSOFileAddress();
+ Address oso_so_addr;
+ if (oso_module->ResolveFileAddress(oso_file_addr, oso_so_addr)) {
+ if (SymbolFile *sym_file = oso_module->GetSymbolFile()) {
+ resolved_flags |= sym_file->ResolveSymbolContext(
+ oso_so_addr, resolve_scope, sc);
+ } else {
+ ObjectFile *obj_file = GetObjectFile();
+ LLDB_LOG(GetLog(DWARFLog::DebugMap),
+ "Failed to get symfile for OSO: {0} in module: {1}",
+ oso_module->GetFileSpec(),
+ obj_file ? obj_file->GetFileSpec()
+ : FileSpec("unknown"));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return resolved_flags;
+}
+
+uint32_t SymbolFileDWARFDebugMap::ResolveSymbolContext(
+ const SourceLocationSpec &src_location_spec,
+ SymbolContextItem resolve_scope, SymbolContextList &sc_list) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ const uint32_t initial = sc_list.GetSize();
+ const uint32_t cu_count = GetNumCompileUnits();
+
+ for (uint32_t i = 0; i < cu_count; ++i) {
+ // If we are checking for inlines, then we need to look through all compile
+ // units no matter if "file_spec" matches.
+ bool resolve = src_location_spec.GetCheckInlines();
+
+ if (!resolve) {
+ FileSpec so_file_spec;
+ if (GetFileSpecForSO(i, so_file_spec))
+ resolve =
+ FileSpec::Match(src_location_spec.GetFileSpec(), so_file_spec);
+ }
+ if (resolve) {
+ SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex(i);
+ if (oso_dwarf)
+ oso_dwarf->ResolveSymbolContext(src_location_spec, resolve_scope,
+ sc_list);
+ }
+ }
+ return sc_list.GetSize() - initial;
+}
+
+void SymbolFileDWARFDebugMap::PrivateFindGlobalVariables(
+ ConstString name, const CompilerDeclContext &parent_decl_ctx,
+ const std::vector<uint32_t>
+ &indexes, // Indexes into the symbol table that match "name"
+ uint32_t max_matches, VariableList &variables) {
+ const size_t match_count = indexes.size();
+ for (size_t i = 0; i < match_count; ++i) {
+ uint32_t oso_idx;
+ CompileUnitInfo *comp_unit_info =
+ GetCompileUnitInfoForSymbolWithIndex(indexes[i], &oso_idx);
+ if (comp_unit_info) {
+ SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex(oso_idx);
+ if (oso_dwarf) {
+ oso_dwarf->FindGlobalVariables(name, parent_decl_ctx, max_matches,
+ variables);
+ if (variables.GetSize() > max_matches)
+ break;
+ }
+ }
+ }
+}
+
+void SymbolFileDWARFDebugMap::FindGlobalVariables(
+ ConstString name, const CompilerDeclContext &parent_decl_ctx,
+ uint32_t max_matches, VariableList &variables) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ uint32_t total_matches = 0;
+
+ ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) {
+ const uint32_t old_size = variables.GetSize();
+ oso_dwarf->FindGlobalVariables(name, parent_decl_ctx, max_matches,
+ variables);
+ const uint32_t oso_matches = variables.GetSize() - old_size;
+ if (oso_matches > 0) {
+ total_matches += oso_matches;
+
+ // Are we getting all matches?
+ if (max_matches == UINT32_MAX)
+ return IterationAction::Continue; // Yep, continue getting everything
+
+ // If we have found enough matches, lets get out
+ if (max_matches >= total_matches)
+ return IterationAction::Stop;
+
+ // Update the max matches for any subsequent calls to find globals in any
+ // other object files with DWARF
+ max_matches -= oso_matches;
+ }
+
+ return IterationAction::Continue;
+ });
+}
+
+void SymbolFileDWARFDebugMap::FindGlobalVariables(
+ const RegularExpression &regex, uint32_t max_matches,
+ VariableList &variables) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ uint32_t total_matches = 0;
+ ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) {
+ const uint32_t old_size = variables.GetSize();
+ oso_dwarf->FindGlobalVariables(regex, max_matches, variables);
+
+ const uint32_t oso_matches = variables.GetSize() - old_size;
+ if (oso_matches > 0) {
+ total_matches += oso_matches;
+
+ // Are we getting all matches?
+ if (max_matches == UINT32_MAX)
+ return IterationAction::Continue; // Yep, continue getting everything
+
+ // If we have found enough matches, lets get out
+ if (max_matches >= total_matches)
+ return IterationAction::Stop;
+
+ // Update the max matches for any subsequent calls to find globals in any
+ // other object files with DWARF
+ max_matches -= oso_matches;
+ }
+
+ return IterationAction::Continue;
+ });
+}
+
+int SymbolFileDWARFDebugMap::SymbolContainsSymbolWithIndex(
+ uint32_t *symbol_idx_ptr, const CompileUnitInfo *comp_unit_info) {
+ const uint32_t symbol_idx = *symbol_idx_ptr;
+
+ if (symbol_idx < comp_unit_info->first_symbol_index)
+ return -1;
+
+ if (symbol_idx <= comp_unit_info->last_symbol_index)
+ return 0;
+
+ return 1;
+}
+
+int SymbolFileDWARFDebugMap::SymbolContainsSymbolWithID(
+ user_id_t *symbol_idx_ptr, const CompileUnitInfo *comp_unit_info) {
+ const user_id_t symbol_id = *symbol_idx_ptr;
+
+ if (symbol_id < comp_unit_info->first_symbol_id)
+ return -1;
+
+ if (symbol_id <= comp_unit_info->last_symbol_id)
+ return 0;
+
+ return 1;
+}
+
+SymbolFileDWARFDebugMap::CompileUnitInfo *
+SymbolFileDWARFDebugMap::GetCompileUnitInfoForSymbolWithIndex(
+ uint32_t symbol_idx, uint32_t *oso_idx_ptr) {
+ const uint32_t oso_index_count = m_compile_unit_infos.size();
+ CompileUnitInfo *comp_unit_info = nullptr;
+ if (oso_index_count) {
+ comp_unit_info = (CompileUnitInfo *)bsearch(
+ &symbol_idx, &m_compile_unit_infos[0], m_compile_unit_infos.size(),
+ sizeof(CompileUnitInfo),
+ (ComparisonFunction)SymbolContainsSymbolWithIndex);
+ }
+
+ if (oso_idx_ptr) {
+ if (comp_unit_info != nullptr)
+ *oso_idx_ptr = comp_unit_info - &m_compile_unit_infos[0];
+ else
+ *oso_idx_ptr = UINT32_MAX;
+ }
+ return comp_unit_info;
+}
+
+SymbolFileDWARFDebugMap::CompileUnitInfo *
+SymbolFileDWARFDebugMap::GetCompileUnitInfoForSymbolWithID(
+ user_id_t symbol_id, uint32_t *oso_idx_ptr) {
+ const uint32_t oso_index_count = m_compile_unit_infos.size();
+ CompileUnitInfo *comp_unit_info = nullptr;
+ if (oso_index_count) {
+ comp_unit_info = (CompileUnitInfo *)::bsearch(
+ &symbol_id, &m_compile_unit_infos[0], m_compile_unit_infos.size(),
+ sizeof(CompileUnitInfo),
+ (ComparisonFunction)SymbolContainsSymbolWithID);
+ }
+
+ if (oso_idx_ptr) {
+ if (comp_unit_info != nullptr)
+ *oso_idx_ptr = comp_unit_info - &m_compile_unit_infos[0];
+ else
+ *oso_idx_ptr = UINT32_MAX;
+ }
+ return comp_unit_info;
+}
+
+static void RemoveFunctionsWithModuleNotEqualTo(const ModuleSP &module_sp,
+ SymbolContextList &sc_list,
+ uint32_t start_idx) {
+ // We found functions in .o files. Not all functions in the .o files will
+ // have made it into the final output file. The ones that did make it into
+ // the final output file will have a section whose module matches the module
+ // from the ObjectFile for this SymbolFile. When the modules don't match,
+ // then we have something that was in a .o file, but doesn't map to anything
+ // in the final executable.
+ uint32_t i = start_idx;
+ while (i < sc_list.GetSize()) {
+ SymbolContext sc;
+ sc_list.GetContextAtIndex(i, sc);
+ if (sc.function) {
+ const SectionSP section_sp(
+ sc.function->GetAddressRange().GetBaseAddress().GetSection());
+ if (section_sp->GetModule() != module_sp) {
+ sc_list.RemoveContextAtIndex(i);
+ continue;
+ }
+ }
+ ++i;
+ }
+}
+
+void SymbolFileDWARFDebugMap::FindFunctions(
+ const Module::LookupInfo &lookup_info,
+ const CompilerDeclContext &parent_decl_ctx, bool include_inlines,
+ SymbolContextList &sc_list) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ LLDB_SCOPED_TIMERF("SymbolFileDWARFDebugMap::FindFunctions (name = %s)",
+ lookup_info.GetLookupName().GetCString());
+
+ ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) {
+ uint32_t sc_idx = sc_list.GetSize();
+ oso_dwarf->FindFunctions(lookup_info, parent_decl_ctx, include_inlines,
+ sc_list);
+ if (!sc_list.IsEmpty()) {
+ RemoveFunctionsWithModuleNotEqualTo(m_objfile_sp->GetModule(), sc_list,
+ sc_idx);
+ }
+ return IterationAction::Continue;
+ });
+}
+
+void SymbolFileDWARFDebugMap::FindFunctions(const RegularExpression &regex,
+ bool include_inlines,
+ SymbolContextList &sc_list) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ LLDB_SCOPED_TIMERF("SymbolFileDWARFDebugMap::FindFunctions (regex = '%s')",
+ regex.GetText().str().c_str());
+
+ ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) {
+ uint32_t sc_idx = sc_list.GetSize();
+
+ oso_dwarf->FindFunctions(regex, include_inlines, sc_list);
+ if (!sc_list.IsEmpty()) {
+ RemoveFunctionsWithModuleNotEqualTo(m_objfile_sp->GetModule(), sc_list,
+ sc_idx);
+ }
+ return IterationAction::Continue;
+ });
+}
+
+void SymbolFileDWARFDebugMap::GetTypes(SymbolContextScope *sc_scope,
+ lldb::TypeClass type_mask,
+ TypeList &type_list) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ LLDB_SCOPED_TIMERF("SymbolFileDWARFDebugMap::GetTypes (type_mask = 0x%8.8x)",
+ type_mask);
+
+ SymbolFileDWARF *oso_dwarf = nullptr;
+ if (sc_scope) {
+ SymbolContext sc;
+ sc_scope->CalculateSymbolContext(&sc);
+
+ CompileUnitInfo *cu_info = GetCompUnitInfo(sc);
+ if (cu_info) {
+ oso_dwarf = GetSymbolFileByCompUnitInfo(cu_info);
+ if (oso_dwarf)
+ oso_dwarf->GetTypes(sc_scope, type_mask, type_list);
+ }
+ } else {
+ ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) {
+ oso_dwarf->GetTypes(sc_scope, type_mask, type_list);
+ return IterationAction::Continue;
+ });
+ }
+}
+
+std::vector<std::unique_ptr<lldb_private::CallEdge>>
+SymbolFileDWARFDebugMap::ParseCallEdgesInFunction(
+ lldb_private::UserID func_id) {
+ uint32_t oso_idx = GetOSOIndexFromUserID(func_id.GetID());
+ SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex(oso_idx);
+ if (oso_dwarf)
+ return oso_dwarf->ParseCallEdgesInFunction(func_id);
+ return {};
+}
+
+DWARFDIE SymbolFileDWARFDebugMap::FindDefinitionDIE(const DWARFDIE &die) {
+ DWARFDIE result;
+ ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) {
+ result = oso_dwarf->FindDefinitionDIE(die);
+ return result ? IterationAction::Stop : IterationAction::Continue;
+ });
+ return result;
+}
+
+bool SymbolFileDWARFDebugMap::Supports_DW_AT_APPLE_objc_complete_type(
+ SymbolFileDWARF *skip_dwarf_oso) {
+ if (m_supports_DW_AT_APPLE_objc_complete_type == eLazyBoolCalculate) {
+ m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolNo;
+ ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) {
+ if (skip_dwarf_oso != oso_dwarf &&
+ oso_dwarf->Supports_DW_AT_APPLE_objc_complete_type(nullptr)) {
+ m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolYes;
+ return IterationAction::Stop;
+ }
+ return IterationAction::Continue;
+ });
+ }
+ return m_supports_DW_AT_APPLE_objc_complete_type == eLazyBoolYes;
+}
+
+TypeSP SymbolFileDWARFDebugMap::FindCompleteObjCDefinitionTypeForDIE(
+ const DWARFDIE &die, ConstString type_name,
+ bool must_be_implementation) {
+ // If we have a debug map, we will have an Objective-C symbol whose name is
+ // the type name and whose type is eSymbolTypeObjCClass. If we can find that
+ // symbol and find its containing parent, we can locate the .o file that will
+ // contain the implementation definition since it will be scoped inside the
+ // N_SO and we can then locate the SymbolFileDWARF that corresponds to that
+ // N_SO.
+ SymbolFileDWARF *oso_dwarf = nullptr;
+ TypeSP type_sp;
+ ObjectFile *module_objfile = m_objfile_sp->GetModule()->GetObjectFile();
+ if (module_objfile) {
+ Symtab *symtab = module_objfile->GetSymtab();
+ if (symtab) {
+ Symbol *objc_class_symbol = symtab->FindFirstSymbolWithNameAndType(
+ type_name, eSymbolTypeObjCClass, Symtab::eDebugAny,
+ Symtab::eVisibilityAny);
+ if (objc_class_symbol) {
+ // Get the N_SO symbol that contains the objective C class symbol as
+ // this should be the .o file that contains the real definition...
+ const Symbol *source_file_symbol = symtab->GetParent(objc_class_symbol);
+
+ if (source_file_symbol &&
+ source_file_symbol->GetType() == eSymbolTypeSourceFile) {
+ const uint32_t source_file_symbol_idx =
+ symtab->GetIndexForSymbol(source_file_symbol);
+ if (source_file_symbol_idx != UINT32_MAX) {
+ CompileUnitInfo *compile_unit_info =
+ GetCompileUnitInfoForSymbolWithIndex(source_file_symbol_idx,
+ nullptr);
+ if (compile_unit_info) {
+ oso_dwarf = GetSymbolFileByCompUnitInfo(compile_unit_info);
+ if (oso_dwarf) {
+ TypeSP type_sp(oso_dwarf->FindCompleteObjCDefinitionTypeForDIE(
+ die, type_name, must_be_implementation));
+ if (type_sp) {
+ return type_sp;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Only search all .o files for the definition if we don't need the
+ // implementation because otherwise, with a valid debug map we should have
+ // the ObjC class symbol and the code above should have found it.
+ if (!must_be_implementation) {
+ TypeSP type_sp;
+
+ ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) {
+ type_sp = oso_dwarf->FindCompleteObjCDefinitionTypeForDIE(
+ die, type_name, must_be_implementation);
+ return type_sp ? IterationAction::Stop : IterationAction::Continue;
+ });
+
+ return type_sp;
+ }
+ return TypeSP();
+}
+
+void SymbolFileDWARFDebugMap::FindTypes(const TypeQuery &query,
+ TypeResults &results) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) {
+ oso_dwarf->FindTypes(query, results);
+ return results.Done(query) ? IterationAction::Stop
+ : IterationAction::Continue;
+ });
+}
+
+CompilerDeclContext SymbolFileDWARFDebugMap::FindNamespace(
+ lldb_private::ConstString name, const CompilerDeclContext &parent_decl_ctx,
+ bool only_root_namespaces) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ CompilerDeclContext matching_namespace;
+
+ ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) {
+ matching_namespace =
+ oso_dwarf->FindNamespace(name, parent_decl_ctx, only_root_namespaces);
+
+ return matching_namespace ? IterationAction::Stop
+ : IterationAction::Continue;
+ });
+
+ return matching_namespace;
+}
+
+void SymbolFileDWARFDebugMap::DumpClangAST(Stream &s) {
+ ForEachSymbolFile([&s](SymbolFileDWARF *oso_dwarf) {
+ oso_dwarf->DumpClangAST(s);
+ // The underlying assumption is that DumpClangAST(...) will obtain the
+ // AST from the underlying TypeSystem and therefore we only need to do
+ // this once and can stop after the first iteration hence we return true.
+ return IterationAction::Stop;
+ });
+}
+
+bool SymbolFileDWARFDebugMap::GetSeparateDebugInfo(
+ lldb_private::StructuredData::Dictionary &d, bool errors_only) {
+ StructuredData::Array separate_debug_info_files;
+ const uint32_t cu_count = GetNumCompileUnits();
+ for (uint32_t cu_idx = 0; cu_idx < cu_count; ++cu_idx) {
+ const auto &info = m_compile_unit_infos[cu_idx];
+ StructuredData::DictionarySP oso_data =
+ std::make_shared<StructuredData::Dictionary>();
+ oso_data->AddStringItem("so_file", info.so_file.GetPath());
+ oso_data->AddStringItem("oso_path", info.oso_path);
+ oso_data->AddIntegerItem("oso_mod_time",
+ (uint32_t)llvm::sys::toTimeT(info.oso_mod_time));
+
+ bool loaded_successfully = false;
+ if (GetModuleByOSOIndex(cu_idx)) {
+ // If we have a valid pointer to the module, we successfully
+ // loaded the oso if there are no load errors.
+ if (!info.oso_load_error.Fail()) {
+ loaded_successfully = true;
+ }
+ }
+ if (!loaded_successfully) {
+ oso_data->AddStringItem("error", info.oso_load_error.AsCString());
+ }
+ oso_data->AddBooleanItem("loaded", loaded_successfully);
+ if (!errors_only || oso_data->HasKey("error"))
+ separate_debug_info_files.AddItem(oso_data);
+ }
+
+ d.AddStringItem("type", "oso");
+ d.AddStringItem("symfile", GetMainObjectFile()->GetFileSpec().GetPath());
+ d.AddItem("separate-debug-info-files",
+ std::make_shared<StructuredData::Array>(
+ std::move(separate_debug_info_files)));
+ return true;
+}
+
+lldb::CompUnitSP
+SymbolFileDWARFDebugMap::GetCompileUnit(SymbolFileDWARF *oso_dwarf, DWARFCompileUnit &dwarf_cu) {
+ if (oso_dwarf) {
+ const uint32_t cu_count = GetNumCompileUnits();
+ for (uint32_t cu_idx = 0; cu_idx < cu_count; ++cu_idx) {
+ SymbolFileDWARF *oso_symfile =
+ GetSymbolFileByCompUnitInfo(&m_compile_unit_infos[cu_idx]);
+ if (oso_symfile == oso_dwarf) {
+ if (m_compile_unit_infos[cu_idx].compile_units_sps.empty())
+ ParseCompileUnitAtIndex(cu_idx);
+
+ auto &id_to_index_map = m_compile_unit_infos[cu_idx].id_to_index_map;
+ auto it = id_to_index_map.find(dwarf_cu.GetID());
+ if (it != id_to_index_map.end())
+ return m_compile_unit_infos[cu_idx]
+ .compile_units_sps[it->getSecond()];
+ }
+ }
+ }
+ llvm_unreachable("this shouldn't happen");
+}
+
+SymbolFileDWARFDebugMap::CompileUnitInfo *
+SymbolFileDWARFDebugMap::GetCompileUnitInfo(SymbolFileDWARF *oso_dwarf) {
+ if (oso_dwarf) {
+ const uint32_t cu_count = GetNumCompileUnits();
+ for (uint32_t cu_idx = 0; cu_idx < cu_count; ++cu_idx) {
+ SymbolFileDWARF *oso_symfile =
+ GetSymbolFileByCompUnitInfo(&m_compile_unit_infos[cu_idx]);
+ if (oso_symfile == oso_dwarf) {
+ return &m_compile_unit_infos[cu_idx];
+ }
+ }
+ }
+ return nullptr;
+}
+
+void SymbolFileDWARFDebugMap::SetCompileUnit(SymbolFileDWARF *oso_dwarf,
+ const CompUnitSP &cu_sp) {
+ if (oso_dwarf) {
+ const uint32_t cu_count = GetNumCompileUnits();
+ for (uint32_t cu_idx = 0; cu_idx < cu_count; ++cu_idx) {
+ SymbolFileDWARF *oso_symfile =
+ GetSymbolFileByCompUnitInfo(&m_compile_unit_infos[cu_idx]);
+ if (oso_symfile == oso_dwarf) {
+ if (!m_compile_unit_infos[cu_idx].compile_units_sps.empty()) {
+ assert(m_compile_unit_infos[cu_idx].compile_units_sps[0].get() ==
+ cu_sp.get());
+ } else {
+ assert(cu_sp->GetID() == 0 &&
+ "Setting first compile unit but with id different than 0!");
+ auto &compile_units_sps = m_compile_unit_infos[cu_idx].compile_units_sps;
+ compile_units_sps.push_back(cu_sp);
+ m_compile_unit_infos[cu_idx].id_to_index_map.insert(
+ {cu_sp->GetID(), compile_units_sps.size() - 1});
+
+ SetCompileUnitAtIndex(cu_idx, cu_sp);
+ }
+ }
+ }
+ }
+}
+
+CompilerDeclContext
+SymbolFileDWARFDebugMap::GetDeclContextForUID(lldb::user_id_t type_uid) {
+ const uint64_t oso_idx = GetOSOIndexFromUserID(type_uid);
+ if (SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex(oso_idx))
+ return oso_dwarf->GetDeclContextForUID(type_uid);
+ return {};
+}
+
+CompilerDeclContext
+SymbolFileDWARFDebugMap::GetDeclContextContainingUID(lldb::user_id_t type_uid) {
+ const uint64_t oso_idx = GetOSOIndexFromUserID(type_uid);
+ if (SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex(oso_idx))
+ return oso_dwarf->GetDeclContextContainingUID(type_uid);
+ return {};
+}
+
+std::vector<CompilerContext>
+SymbolFileDWARFDebugMap::GetCompilerContextForUID(lldb::user_id_t type_uid) {
+ const uint64_t oso_idx = GetOSOIndexFromUserID(type_uid);
+ if (SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex(oso_idx))
+ return oso_dwarf->GetCompilerContextForUID(type_uid);
+ return {};
+}
+
+void SymbolFileDWARFDebugMap::ParseDeclsForContext(
+ lldb_private::CompilerDeclContext decl_ctx) {
+ ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) {
+ oso_dwarf->ParseDeclsForContext(decl_ctx);
+ return IterationAction::Continue;
+ });
+}
+
+bool SymbolFileDWARFDebugMap::AddOSOFileRange(CompileUnitInfo *cu_info,
+ lldb::addr_t exe_file_addr,
+ lldb::addr_t exe_byte_size,
+ lldb::addr_t oso_file_addr,
+ lldb::addr_t oso_byte_size) {
+ const uint32_t debug_map_idx =
+ m_debug_map.FindEntryIndexThatContains(exe_file_addr);
+ if (debug_map_idx != UINT32_MAX) {
+ DebugMap::Entry *debug_map_entry =
+ m_debug_map.FindEntryThatContains(exe_file_addr);
+ debug_map_entry->data.SetOSOFileAddress(oso_file_addr);
+ addr_t range_size = std::min<addr_t>(exe_byte_size, oso_byte_size);
+ if (range_size == 0) {
+ range_size = std::max<addr_t>(exe_byte_size, oso_byte_size);
+ if (range_size == 0)
+ range_size = 1;
+ }
+ cu_info->file_range_map.Append(
+ FileRangeMap::Entry(oso_file_addr, range_size, exe_file_addr));
+ return true;
+ }
+ return false;
+}
+
+void SymbolFileDWARFDebugMap::FinalizeOSOFileRanges(CompileUnitInfo *cu_info) {
+ cu_info->file_range_map.Sort();
+#if defined(DEBUG_OSO_DMAP)
+ const FileRangeMap &oso_file_range_map = cu_info->GetFileRangeMap(this);
+ const size_t n = oso_file_range_map.GetSize();
+ printf("SymbolFileDWARFDebugMap::FinalizeOSOFileRanges (cu_info = %p) %s\n",
+ cu_info, cu_info->oso_sp->module_sp->GetFileSpec().GetPath().c_str());
+ for (size_t i = 0; i < n; ++i) {
+ const FileRangeMap::Entry &entry = oso_file_range_map.GetEntryRef(i);
+ printf("oso [0x%16.16" PRIx64 " - 0x%16.16" PRIx64
+ ") ==> exe [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ")\n",
+ entry.GetRangeBase(), entry.GetRangeEnd(), entry.data,
+ entry.data + entry.GetByteSize());
+ }
+#endif
+}
+
+lldb::addr_t
+SymbolFileDWARFDebugMap::LinkOSOFileAddress(SymbolFileDWARF *oso_symfile,
+ lldb::addr_t oso_file_addr) {
+ CompileUnitInfo *cu_info = GetCompileUnitInfo(oso_symfile);
+ if (cu_info) {
+ const FileRangeMap::Entry *oso_range_entry =
+ cu_info->GetFileRangeMap(this).FindEntryThatContains(oso_file_addr);
+ if (oso_range_entry) {
+ const DebugMap::Entry *debug_map_entry =
+ m_debug_map.FindEntryThatContains(oso_range_entry->data);
+ if (debug_map_entry) {
+ const lldb::addr_t offset =
+ oso_file_addr - oso_range_entry->GetRangeBase();
+ const lldb::addr_t exe_file_addr =
+ debug_map_entry->GetRangeBase() + offset;
+ return exe_file_addr;
+ }
+ }
+ }
+ return LLDB_INVALID_ADDRESS;
+}
+
+bool SymbolFileDWARFDebugMap::LinkOSOAddress(Address &addr) {
+ // Make sure this address hasn't been fixed already
+ Module *exe_module = GetObjectFile()->GetModule().get();
+ Module *addr_module = addr.GetModule().get();
+ if (addr_module == exe_module)
+ return true; // Address is already in terms of the main executable module
+
+ CompileUnitInfo *cu_info = GetCompileUnitInfo(
+ GetSymbolFileAsSymbolFileDWARF(addr_module->GetSymbolFile()));
+ if (cu_info) {
+ const lldb::addr_t oso_file_addr = addr.GetFileAddress();
+ const FileRangeMap::Entry *oso_range_entry =
+ cu_info->GetFileRangeMap(this).FindEntryThatContains(oso_file_addr);
+ if (oso_range_entry) {
+ const DebugMap::Entry *debug_map_entry =
+ m_debug_map.FindEntryThatContains(oso_range_entry->data);
+ if (debug_map_entry) {
+ const lldb::addr_t offset =
+ oso_file_addr - oso_range_entry->GetRangeBase();
+ const lldb::addr_t exe_file_addr =
+ debug_map_entry->GetRangeBase() + offset;
+ return exe_module->ResolveFileAddress(exe_file_addr, addr);
+ }
+ }
+ }
+ return true;
+}
+
+LineTable *SymbolFileDWARFDebugMap::LinkOSOLineTable(SymbolFileDWARF *oso_dwarf,
+ LineTable *line_table) {
+ CompileUnitInfo *cu_info = GetCompileUnitInfo(oso_dwarf);
+ if (cu_info)
+ return line_table->LinkLineTable(cu_info->GetFileRangeMap(this));
+ return nullptr;
+}
+
+size_t
+SymbolFileDWARFDebugMap::AddOSOARanges(SymbolFileDWARF *dwarf2Data,
+ DWARFDebugAranges *debug_aranges) {
+ size_t num_line_entries_added = 0;
+ if (debug_aranges && dwarf2Data) {
+ CompileUnitInfo *compile_unit_info = GetCompileUnitInfo(dwarf2Data);
+ if (compile_unit_info) {
+ const FileRangeMap &file_range_map =
+ compile_unit_info->GetFileRangeMap(this);
+ for (size_t idx = 0; idx < file_range_map.GetSize(); idx++) {
+ const FileRangeMap::Entry *entry = file_range_map.GetEntryAtIndex(idx);
+ if (entry) {
+ debug_aranges->AppendRange(*dwarf2Data->GetFileIndex(),
+ entry->GetRangeBase(),
+ entry->GetRangeEnd());
+ num_line_entries_added++;
+ }
+ }
+ }
+ }
+ return num_line_entries_added;
+}
+
+ModuleList SymbolFileDWARFDebugMap::GetDebugInfoModules() {
+ ModuleList oso_modules;
+ ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) {
+ ObjectFile *oso_objfile = oso_dwarf->GetObjectFile();
+ if (oso_objfile) {
+ ModuleSP module_sp = oso_objfile->GetModule();
+ if (module_sp)
+ oso_modules.Append(module_sp);
+ }
+ return IterationAction::Continue;
+ });
+ return oso_modules;
+}
+
+Status SymbolFileDWARFDebugMap::CalculateFrameVariableError(StackFrame &frame) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+
+ // We need to make sure that our PC value from the frame matches the module
+ // for this object file since we will lookup the PC file address in the debug
+ // map below.
+ Address pc_addr = frame.GetFrameCodeAddress();
+ if (pc_addr.GetModule() == m_objfile_sp->GetModule()) {
+ Symtab *symtab = m_objfile_sp->GetSymtab();
+ if (symtab) {
+ const DebugMap::Entry *debug_map_entry =
+ m_debug_map.FindEntryThatContains(pc_addr.GetFileAddress());
+ if (debug_map_entry) {
+ Symbol *symbol =
+ symtab->SymbolAtIndex(debug_map_entry->data.GetExeSymbolIndex());
+ if (symbol) {
+ uint32_t oso_idx = 0;
+ CompileUnitInfo *comp_unit_info =
+ GetCompileUnitInfoForSymbolWithID(symbol->GetID(), &oso_idx);
+ if (comp_unit_info) {
+ Module *oso_module = GetModuleByCompUnitInfo(comp_unit_info);
+ if (oso_module) {
+ // Check the .o file's DWARF in case it has an error to display.
+ SymbolFile *oso_sym_file = oso_module->GetSymbolFile();
+ if (oso_sym_file)
+ return oso_sym_file->GetFrameVariableError(frame);
+ }
+ // If we don't have a valid OSO module here, then something went
+ // wrong as we have a symbol for the address in the debug map, but
+ // we weren't able to open the .o file. Display an appropriate
+ // error
+ if (comp_unit_info->oso_load_error.Fail())
+ return comp_unit_info->oso_load_error;
+ else
+ return Status("unable to load debug map object file \"%s\" "
+ "exist, debug info will not be loaded",
+ comp_unit_info->oso_path.GetCString());
+ }
+ }
+ }
+ }
+ }
+ return Status();
+}
+
+void SymbolFileDWARFDebugMap::GetCompileOptions(
+ std::unordered_map<lldb::CompUnitSP, lldb_private::Args> &args) {
+
+ ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) {
+ oso_dwarf->GetCompileOptions(args);
+ return IterationAction::Continue;
+ });
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
new file mode 100644
index 000000000000..34cb52e5b601
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
@@ -0,0 +1,398 @@
+//===-- SymbolFileDWARFDebugMap.h ------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_SYMBOLFILEDWARFDEBUGMAP_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_SYMBOLFILEDWARFDEBUGMAP_H
+
+#include "DIERef.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Utility/RangeMap.h"
+#include "llvm/Support/Chrono.h"
+#include <bitset>
+#include <map>
+#include <optional>
+#include <vector>
+
+#include "UniqueDWARFASTType.h"
+#include "lldb/Utility/StructuredData.h"
+#include "lldb/lldb-private-enumerations.h"
+
+class DWARFASTParserClang;
+
+namespace lldb_private::plugin {
+namespace dwarf {
+class SymbolFileDWARF;
+class DWARFCompileUnit;
+class DWARFDebugAranges;
+class DWARFDeclContext;
+
+class SymbolFileDWARFDebugMap : public SymbolFileCommon {
+ /// LLVM RTTI support.
+ static char ID;
+
+public:
+ /// LLVM RTTI support.
+ /// \{
+ bool isA(const void *ClassID) const override {
+ return ClassID == &ID || SymbolFileCommon::isA(ClassID);
+ }
+ static bool classof(const SymbolFile *obj) { return obj->isA(&ID); }
+ /// \}
+
+ // Static Functions
+ static void Initialize();
+
+ static void Terminate();
+
+ static llvm::StringRef GetPluginNameStatic() { return "dwarf-debugmap"; }
+
+ static llvm::StringRef GetPluginDescriptionStatic();
+
+ static SymbolFile *CreateInstance(lldb::ObjectFileSP objfile_sp);
+
+ // Constructors and Destructors
+ SymbolFileDWARFDebugMap(lldb::ObjectFileSP objfile_sp);
+ ~SymbolFileDWARFDebugMap() override;
+
+ uint32_t CalculateAbilities() override;
+ void InitializeObject() override;
+
+ // Compile Unit function calls
+ lldb::LanguageType ParseLanguage(CompileUnit &comp_unit) override;
+ XcodeSDK ParseXcodeSDK(CompileUnit &comp_unit) override;
+ llvm::SmallSet<lldb::LanguageType, 4>
+ ParseAllLanguages(CompileUnit &comp_unit) override;
+ size_t ParseFunctions(CompileUnit &comp_unit) override;
+ bool ParseLineTable(CompileUnit &comp_unit) override;
+ bool ParseDebugMacros(CompileUnit &comp_unit) override;
+
+ bool ForEachExternalModule(CompileUnit &, llvm::DenseSet<SymbolFile *> &,
+ llvm::function_ref<bool(Module &)>) override;
+
+ bool ParseSupportFiles(CompileUnit &comp_unit,
+ SupportFileList &support_files) override;
+
+ bool ParseIsOptimized(CompileUnit &comp_unit) override;
+
+ size_t ParseTypes(CompileUnit &comp_unit) override;
+
+ bool
+ ParseImportedModules(const SymbolContext &sc,
+ std::vector<SourceModule> &imported_modules) override;
+ size_t ParseBlocksRecursive(Function &func) override;
+ size_t ParseVariablesForContext(const SymbolContext &sc) override;
+
+ Type *ResolveTypeUID(lldb::user_id_t type_uid) override;
+ std::optional<ArrayInfo>
+ GetDynamicArrayInfoForUID(lldb::user_id_t type_uid,
+ const ExecutionContext *exe_ctx) override;
+
+ CompilerDeclContext GetDeclContextForUID(lldb::user_id_t uid) override;
+ CompilerDeclContext GetDeclContextContainingUID(lldb::user_id_t uid) override;
+ std::vector<CompilerContext>
+ GetCompilerContextForUID(lldb::user_id_t uid) override;
+ void ParseDeclsForContext(CompilerDeclContext decl_ctx) override;
+
+ bool CompleteType(CompilerType &compiler_type) override;
+ uint32_t ResolveSymbolContext(const Address &so_addr,
+ lldb::SymbolContextItem resolve_scope,
+ SymbolContext &sc) override;
+ uint32_t ResolveSymbolContext(const SourceLocationSpec &src_location_spec,
+ lldb::SymbolContextItem resolve_scope,
+ SymbolContextList &sc_list) override;
+
+ Status CalculateFrameVariableError(StackFrame &frame) override;
+
+ void FindGlobalVariables(ConstString name,
+ const CompilerDeclContext &parent_decl_ctx,
+ uint32_t max_matches,
+ VariableList &variables) override;
+ void FindGlobalVariables(const RegularExpression &regex, uint32_t max_matches,
+ VariableList &variables) override;
+ void FindFunctions(const Module::LookupInfo &lookup_info,
+ const CompilerDeclContext &parent_decl_ctx,
+ bool include_inlines, SymbolContextList &sc_list) override;
+ void FindFunctions(const RegularExpression &regex, bool include_inlines,
+ SymbolContextList &sc_list) override;
+ void FindTypes(const lldb_private::TypeQuery &match,
+ lldb_private::TypeResults &results) override;
+ CompilerDeclContext FindNamespace(ConstString name,
+ const CompilerDeclContext &parent_decl_ctx,
+ bool only_root_namespaces) override;
+ void GetTypes(SymbolContextScope *sc_scope, lldb::TypeClass type_mask,
+ TypeList &type_list) override;
+ std::vector<std::unique_ptr<CallEdge>>
+ ParseCallEdgesInFunction(UserID func_id) override;
+
+ void DumpClangAST(Stream &s) override;
+
+ /// List separate oso files.
+ bool GetSeparateDebugInfo(StructuredData::Dictionary &d,
+ bool errors_only) override;
+
+ // PluginInterface protocol
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+ // Statistics overrides.
+ ModuleList GetDebugInfoModules() override;
+
+ void
+ GetCompileOptions(std::unordered_map<lldb::CompUnitSP, Args> &args) override;
+
+protected:
+ enum { kHaveInitializedOSOs = (1 << 0), kNumFlags };
+
+ friend class DebugMapModule;
+ friend class ::DWARFASTParserClang;
+ friend class DWARFCompileUnit;
+ friend class SymbolFileDWARF;
+ struct OSOInfo {
+ lldb::ModuleSP module_sp;
+
+ OSOInfo() : module_sp() {}
+ };
+
+ typedef std::shared_ptr<OSOInfo> OSOInfoSP;
+
+ typedef RangeDataVector<lldb::addr_t, lldb::addr_t, lldb::addr_t>
+ FileRangeMap;
+
+ // Class specific types
+ struct CompileUnitInfo {
+ FileSpec so_file;
+ ConstString oso_path;
+ llvm::sys::TimePoint<> oso_mod_time;
+ Status oso_load_error;
+ OSOInfoSP oso_sp;
+ /// The compile units that an object file contains.
+ llvm::SmallVector<lldb::CompUnitSP, 2> compile_units_sps;
+ /// A map from the compile unit ID to its index in the vector.
+ llvm::SmallDenseMap<uint64_t, uint64_t, 2> id_to_index_map;
+ uint32_t first_symbol_index = UINT32_MAX;
+ uint32_t last_symbol_index = UINT32_MAX;
+ uint32_t first_symbol_id = UINT32_MAX;
+ uint32_t last_symbol_id = UINT32_MAX;
+ FileRangeMap file_range_map;
+ bool file_range_map_valid = false;
+
+ CompileUnitInfo() = default;
+
+ const FileRangeMap &GetFileRangeMap(SymbolFileDWARFDebugMap *exe_symfile);
+ };
+
+ // Protected Member Functions
+ void InitOSO();
+
+ /// This function actually returns the number of object files, which may be
+ /// less than the actual number of compile units, since an object file may
+ /// contain more than one compile unit. SymbolFileDWARFDebugMap looks up the
+ /// number of compile units by reading the nlist symbol table, which
+ /// currently, on macOS, only reports one compile unit per object file, and
+ /// there's no efficient way to calculate the actual number of compile units
+ /// upfront.
+ uint32_t CalculateNumCompileUnits() override;
+
+ /// This function actually returns the first compile unit the object file at
+ /// the given index contains.
+ lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index) override;
+
+ static uint32_t GetOSOIndexFromUserID(lldb::user_id_t uid) {
+ std::optional<uint32_t> OsoNum = DIERef(uid).file_index();
+ lldbassert(OsoNum && "Invalid OSO Index");
+ return *OsoNum;
+ }
+
+ static SymbolFileDWARF *GetSymbolFileAsSymbolFileDWARF(SymbolFile *sym_file);
+
+ bool GetFileSpecForSO(uint32_t oso_idx, FileSpec &file_spec);
+
+ CompileUnitInfo *GetCompUnitInfo(const SymbolContext &sc);
+ CompileUnitInfo *GetCompUnitInfo(const CompileUnit &comp_unit);
+
+ size_t GetCompUnitInfosForModule(const Module *oso_module,
+ std::vector<CompileUnitInfo *> &cu_infos);
+
+ Module *GetModuleByCompUnitInfo(CompileUnitInfo *comp_unit_info);
+
+ Module *GetModuleByOSOIndex(uint32_t oso_idx);
+
+ ObjectFile *GetObjectFileByCompUnitInfo(CompileUnitInfo *comp_unit_info);
+
+ ObjectFile *GetObjectFileByOSOIndex(uint32_t oso_idx);
+
+ uint32_t GetCompUnitInfoIndex(const CompileUnitInfo *comp_unit_info);
+
+ SymbolFileDWARF *GetSymbolFile(const SymbolContext &sc);
+ SymbolFileDWARF *GetSymbolFile(const CompileUnit &comp_unit);
+
+ SymbolFileDWARF *GetSymbolFileByCompUnitInfo(CompileUnitInfo *comp_unit_info);
+
+ SymbolFileDWARF *GetSymbolFileByOSOIndex(uint32_t oso_idx);
+
+ /// If closure returns \ref IterationAction::Continue, iteration
+ /// continues. Otherwise, iteration terminates.
+ void
+ ForEachSymbolFile(std::function<IterationAction(SymbolFileDWARF *)> closure) {
+ for (uint32_t oso_idx = 0, num_oso_idxs = m_compile_unit_infos.size();
+ oso_idx < num_oso_idxs; ++oso_idx) {
+ if (SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex(oso_idx)) {
+ if (closure(oso_dwarf) == IterationAction::Stop)
+ return;
+ }
+ }
+ }
+
+ CompileUnitInfo *GetCompileUnitInfoForSymbolWithIndex(uint32_t symbol_idx,
+ uint32_t *oso_idx_ptr);
+
+ CompileUnitInfo *GetCompileUnitInfoForSymbolWithID(lldb::user_id_t symbol_id,
+ uint32_t *oso_idx_ptr);
+
+ static int
+ SymbolContainsSymbolWithIndex(uint32_t *symbol_idx_ptr,
+ const CompileUnitInfo *comp_unit_info);
+
+ static int SymbolContainsSymbolWithID(lldb::user_id_t *symbol_idx_ptr,
+ const CompileUnitInfo *comp_unit_info);
+
+ void
+ PrivateFindGlobalVariables(ConstString name,
+ const CompilerDeclContext &parent_decl_ctx,
+ const std::vector<uint32_t> &name_symbol_indexes,
+ uint32_t max_matches, VariableList &variables);
+
+ void SetCompileUnit(SymbolFileDWARF *oso_dwarf,
+ const lldb::CompUnitSP &cu_sp);
+
+ /// Returns the compile unit associated with the dwarf compile unit. This may
+ /// be one of the extra compile units an object file contains which isn't
+ /// reachable by ParseCompileUnitAtIndex(uint32_t).
+ lldb::CompUnitSP GetCompileUnit(SymbolFileDWARF *oso_dwarf,
+ DWARFCompileUnit &dwarf_cu);
+
+ CompileUnitInfo *GetCompileUnitInfo(SymbolFileDWARF *oso_dwarf);
+
+ DWARFDIE FindDefinitionDIE(const DWARFDIE &die);
+
+ bool Supports_DW_AT_APPLE_objc_complete_type(SymbolFileDWARF *skip_dwarf_oso);
+
+ lldb::TypeSP FindCompleteObjCDefinitionTypeForDIE(
+ const DWARFDIE &die, ConstString type_name, bool must_be_implementation);
+
+ llvm::DenseMap<lldb::opaque_compiler_type_t, DIERef> &
+ GetForwardDeclCompilerTypeToDIE() {
+ return m_forward_decl_compiler_type_to_die;
+ }
+
+ UniqueDWARFASTTypeMap &GetUniqueDWARFASTTypeMap() {
+ return m_unique_ast_type_map;
+ }
+
+ // OSOEntry
+ class OSOEntry {
+ public:
+ OSOEntry() = default;
+
+ OSOEntry(uint32_t exe_sym_idx, lldb::addr_t oso_file_addr)
+ : m_exe_sym_idx(exe_sym_idx), m_oso_file_addr(oso_file_addr) {}
+
+ uint32_t GetExeSymbolIndex() const { return m_exe_sym_idx; }
+
+ bool operator<(const OSOEntry &rhs) const {
+ return m_exe_sym_idx < rhs.m_exe_sym_idx;
+ }
+
+ lldb::addr_t GetOSOFileAddress() const { return m_oso_file_addr; }
+
+ void SetOSOFileAddress(lldb::addr_t oso_file_addr) {
+ m_oso_file_addr = oso_file_addr;
+ }
+
+ protected:
+ uint32_t m_exe_sym_idx = UINT32_MAX;
+ lldb::addr_t m_oso_file_addr = LLDB_INVALID_ADDRESS;
+ };
+
+ typedef RangeDataVector<lldb::addr_t, lldb::addr_t, OSOEntry> DebugMap;
+
+ // Member Variables
+ std::bitset<kNumFlags> m_flags;
+ std::vector<CompileUnitInfo> m_compile_unit_infos;
+ std::vector<uint32_t> m_func_indexes; // Sorted by address
+ std::vector<uint32_t> m_glob_indexes;
+ std::map<std::pair<ConstString, llvm::sys::TimePoint<>>, OSOInfoSP> m_oso_map;
+ // A map from CompilerType to the struct/class/union/enum DIE (might be a
+ // declaration or a definition) that is used to construct it.
+ llvm::DenseMap<lldb::opaque_compiler_type_t, DIERef>
+ m_forward_decl_compiler_type_to_die;
+ UniqueDWARFASTTypeMap m_unique_ast_type_map;
+ LazyBool m_supports_DW_AT_APPLE_objc_complete_type;
+ DebugMap m_debug_map;
+
+ // When an object file from the debug map gets parsed in
+ // SymbolFileDWARF, it needs to tell the debug map about the object
+ // files addresses by calling this function once for each N_FUN,
+ // N_GSYM and N_STSYM and after all entries in the debug map have
+ // been matched up, FinalizeOSOFileRanges() should be called.
+ bool AddOSOFileRange(CompileUnitInfo *cu_info, lldb::addr_t exe_file_addr,
+ lldb::addr_t exe_byte_size, lldb::addr_t oso_file_addr,
+ lldb::addr_t oso_byte_size);
+
+ // Called after calling AddOSOFileRange() for each object file debug
+ // map entry to finalize the info for the unlinked compile unit.
+ void FinalizeOSOFileRanges(CompileUnitInfo *cu_info);
+
+ /// Convert \a addr from a .o file address, to an executable address.
+ ///
+ /// \param[in] addr
+ /// A section offset address from a .o file
+ ///
+ /// \return
+ /// Returns true if \a addr was converted to be an executable
+ /// section/offset address, false otherwise.
+ bool LinkOSOAddress(Address &addr);
+
+ /// Convert a .o file "file address" to an executable "file address".
+ ///
+ /// \param[in] oso_symfile
+ /// The DWARF symbol file that contains \a oso_file_addr
+ ///
+ /// \param[in] oso_file_addr
+ /// A .o file "file address" to convert.
+ ///
+ /// \return
+ /// LLDB_INVALID_ADDRESS if \a oso_file_addr is not in the
+ /// linked executable, otherwise a valid "file address" from the
+ /// linked executable that contains the debug map.
+ lldb::addr_t LinkOSOFileAddress(SymbolFileDWARF *oso_symfile,
+ lldb::addr_t oso_file_addr);
+
+ /// Given a line table full of lines with "file addresses" that are
+ /// for a .o file represented by \a oso_symfile, link a new line table
+ /// and return it.
+ ///
+ /// \param[in] oso_symfile
+ /// The DWARF symbol file that produced the \a line_table
+ ///
+ /// \param[in] line_table
+ /// A pointer to the line table.
+ ///
+ /// \return
+ /// Returns a valid line table full of linked addresses, or NULL
+ /// if none of the line table addresses exist in the main
+ /// executable.
+ LineTable *LinkOSOLineTable(SymbolFileDWARF *oso_symfile,
+ LineTable *line_table);
+
+ size_t AddOSOARanges(SymbolFileDWARF *dwarf2Data,
+ DWARFDebugAranges *debug_aranges);
+};
+} // namespace dwarf
+} // namespace lldb_private::plugin
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_SYMBOLFILEDWARFDEBUGMAP_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp
new file mode 100644
index 000000000000..49632e1d8911
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp
@@ -0,0 +1,180 @@
+//===-- SymbolFileDWARFDwo.cpp --------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolFileDWARFDwo.h"
+
+#include "lldb/Core/Section.h"
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "llvm/Support/Casting.h"
+
+#include "DWARFCompileUnit.h"
+#include "DWARFDebugInfo.h"
+#include "DWARFUnit.h"
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::plugin::dwarf;
+
+char SymbolFileDWARFDwo::ID;
+
+SymbolFileDWARFDwo::SymbolFileDWARFDwo(SymbolFileDWARF &base_symbol_file,
+ ObjectFileSP objfile, uint32_t id)
+ : SymbolFileDWARF(objfile, objfile->GetSectionList(
+ /*update_module_section_list*/ false)),
+ m_base_symbol_file(base_symbol_file) {
+ SetFileIndex(id);
+
+ // Parsing of the dwarf unit index is not thread-safe, so we need to prime it
+ // to enable subsequent concurrent lookups.
+ m_context.GetAsLLVM().getCUIndex();
+}
+
+DWARFCompileUnit *SymbolFileDWARFDwo::GetDWOCompileUnitForHash(uint64_t hash) {
+ if (const llvm::DWARFUnitIndex &index = m_context.GetAsLLVM().getCUIndex()) {
+ if (const llvm::DWARFUnitIndex::Entry *entry = index.getFromHash(hash)) {
+ if (auto *unit_contrib = entry->getContribution())
+ return llvm::dyn_cast_or_null<DWARFCompileUnit>(
+ DebugInfo().GetUnitAtOffset(DIERef::Section::DebugInfo,
+ unit_contrib->getOffset()));
+ }
+ return nullptr;
+ }
+
+ DWARFCompileUnit *cu = FindSingleCompileUnit();
+ if (!cu)
+ return nullptr;
+ std::optional<uint64_t> dwo_id = cu->GetDWOId();
+ if (!dwo_id || hash != *dwo_id)
+ return nullptr;
+ return cu;
+}
+
+DWARFCompileUnit *SymbolFileDWARFDwo::FindSingleCompileUnit() {
+ DWARFDebugInfo &debug_info = DebugInfo();
+
+ // Right now we only support dwo files with one compile unit. If we don't have
+ // type units, we can just check for the unit count.
+ if (!debug_info.ContainsTypeUnits() && debug_info.GetNumUnits() == 1)
+ return llvm::cast<DWARFCompileUnit>(debug_info.GetUnitAtIndex(0));
+
+ // Otherwise, we have to run through all units, and find the compile unit that
+ // way.
+ DWARFCompileUnit *cu = nullptr;
+ for (size_t i = 0; i < debug_info.GetNumUnits(); ++i) {
+ if (auto *candidate =
+ llvm::dyn_cast<DWARFCompileUnit>(debug_info.GetUnitAtIndex(i))) {
+ if (cu)
+ return nullptr; // More that one CU found.
+ cu = candidate;
+ }
+ }
+ return cu;
+}
+
+lldb::offset_t SymbolFileDWARFDwo::GetVendorDWARFOpcodeSize(
+ const lldb_private::DataExtractor &data, const lldb::offset_t data_offset,
+ const uint8_t op) const {
+ return GetBaseSymbolFile().GetVendorDWARFOpcodeSize(data, data_offset, op);
+}
+
+uint64_t SymbolFileDWARFDwo::GetDebugInfoSize(bool load_all_debug_info) {
+ // Directly get debug info from current dwo object file's section list
+ // instead of asking SymbolFileCommon::GetDebugInfo() which parses from
+ // owning module which is wrong.
+ SectionList *section_list =
+ m_objfile_sp->GetSectionList(/*update_module_section_list=*/false);
+ if (section_list)
+ return section_list->GetDebugInfoSize();
+ return 0;
+}
+
+bool SymbolFileDWARFDwo::ParseVendorDWARFOpcode(
+ uint8_t op, const lldb_private::DataExtractor &opcodes,
+ lldb::offset_t &offset, std::vector<lldb_private::Value> &stack) const {
+ return GetBaseSymbolFile().ParseVendorDWARFOpcode(op, opcodes, offset, stack);
+}
+
+SymbolFileDWARF::DIEToTypePtr &SymbolFileDWARFDwo::GetDIEToType() {
+ return GetBaseSymbolFile().GetDIEToType();
+}
+
+SymbolFileDWARF::DIEToVariableSP &SymbolFileDWARFDwo::GetDIEToVariable() {
+ return GetBaseSymbolFile().GetDIEToVariable();
+}
+
+llvm::DenseMap<lldb::opaque_compiler_type_t, DIERef> &
+SymbolFileDWARFDwo::GetForwardDeclCompilerTypeToDIE() {
+ return GetBaseSymbolFile().GetForwardDeclCompilerTypeToDIE();
+}
+
+void SymbolFileDWARFDwo::GetObjCMethods(
+ lldb_private::ConstString class_name,
+ llvm::function_ref<bool(DWARFDIE die)> callback) {
+ GetBaseSymbolFile().GetObjCMethods(class_name, callback);
+}
+
+UniqueDWARFASTTypeMap &SymbolFileDWARFDwo::GetUniqueDWARFASTTypeMap() {
+ return GetBaseSymbolFile().GetUniqueDWARFASTTypeMap();
+}
+
+DWARFDIE SymbolFileDWARFDwo::FindDefinitionDIE(const DWARFDIE &die) {
+ return GetBaseSymbolFile().FindDefinitionDIE(die);
+}
+
+lldb::TypeSP SymbolFileDWARFDwo::FindCompleteObjCDefinitionTypeForDIE(
+ const DWARFDIE &die, lldb_private::ConstString type_name,
+ bool must_be_implementation) {
+ return GetBaseSymbolFile().FindCompleteObjCDefinitionTypeForDIE(
+ die, type_name, must_be_implementation);
+}
+
+llvm::Expected<lldb::TypeSystemSP>
+SymbolFileDWARFDwo::GetTypeSystemForLanguage(LanguageType language) {
+ return GetBaseSymbolFile().GetTypeSystemForLanguage(language);
+}
+
+DWARFDIE
+SymbolFileDWARFDwo::GetDIE(const DIERef &die_ref) {
+ if (die_ref.file_index() == GetFileIndex())
+ return DebugInfo().GetDIE(die_ref.section(), die_ref.die_offset());
+ return GetBaseSymbolFile().GetDIE(die_ref);
+}
+
+void SymbolFileDWARFDwo::FindGlobalVariables(
+ ConstString name, const CompilerDeclContext &parent_decl_ctx,
+ uint32_t max_matches, VariableList &variables) {
+ GetBaseSymbolFile().FindGlobalVariables(name, parent_decl_ctx, max_matches,
+ variables);
+}
+
+bool SymbolFileDWARFDwo::GetDebugInfoIndexWasLoadedFromCache() const {
+ return GetBaseSymbolFile().GetDebugInfoIndexWasLoadedFromCache();
+}
+void SymbolFileDWARFDwo::SetDebugInfoIndexWasLoadedFromCache() {
+ GetBaseSymbolFile().SetDebugInfoIndexWasLoadedFromCache();
+}
+bool SymbolFileDWARFDwo::GetDebugInfoIndexWasSavedToCache() const {
+ return GetBaseSymbolFile().GetDebugInfoIndexWasSavedToCache();
+}
+void SymbolFileDWARFDwo::SetDebugInfoIndexWasSavedToCache() {
+ GetBaseSymbolFile().SetDebugInfoIndexWasSavedToCache();
+}
+bool SymbolFileDWARFDwo::GetDebugInfoHadFrameVariableErrors() const {
+ return GetBaseSymbolFile().GetDebugInfoHadFrameVariableErrors();
+}
+void SymbolFileDWARFDwo::SetDebugInfoHadFrameVariableErrors() {
+ return GetBaseSymbolFile().SetDebugInfoHadFrameVariableErrors();
+}
+
+SymbolFileDWARF *
+SymbolFileDWARFDwo::GetDIERefSymbolFile(const DIERef &die_ref) {
+ return GetBaseSymbolFile().GetDIERefSymbolFile(die_ref);
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h
new file mode 100644
index 000000000000..15c28fefd81f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h
@@ -0,0 +1,98 @@
+//===-- SymbolFileDWARFDwo.h ------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_SYMBOLFILEDWARFDWO_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_SYMBOLFILEDWARFDWO_H
+
+#include "SymbolFileDWARF.h"
+#include <optional>
+
+namespace lldb_private::plugin {
+namespace dwarf {
+class SymbolFileDWARFDwo : public SymbolFileDWARF {
+ /// LLVM RTTI support.
+ static char ID;
+
+public:
+ /// LLVM RTTI support.
+ /// \{
+ bool isA(const void *ClassID) const override {
+ return ClassID == &ID || SymbolFileDWARF::isA(ClassID);
+ }
+ static bool classof(const SymbolFile *obj) { return obj->isA(&ID); }
+ /// \}
+
+ SymbolFileDWARFDwo(SymbolFileDWARF &m_base_symbol_file,
+ lldb::ObjectFileSP objfile, uint32_t id);
+
+ ~SymbolFileDWARFDwo() override = default;
+
+ DWARFCompileUnit *GetDWOCompileUnitForHash(uint64_t hash);
+
+ void GetObjCMethods(ConstString class_name,
+ llvm::function_ref<bool(DWARFDIE die)> callback) override;
+
+ llvm::Expected<lldb::TypeSystemSP>
+ GetTypeSystemForLanguage(lldb::LanguageType language) override;
+
+ DWARFDIE
+ GetDIE(const DIERef &die_ref) override;
+
+ lldb::offset_t GetVendorDWARFOpcodeSize(const DataExtractor &data,
+ const lldb::offset_t data_offset,
+ const uint8_t op) const override;
+
+ uint64_t GetDebugInfoSize(bool load_all_debug_info = false) override;
+
+ bool ParseVendorDWARFOpcode(uint8_t op, const DataExtractor &opcodes,
+ lldb::offset_t &offset,
+ std::vector<Value> &stack) const override;
+
+ void FindGlobalVariables(ConstString name,
+ const CompilerDeclContext &parent_decl_ctx,
+ uint32_t max_matches,
+ VariableList &variables) override;
+
+ SymbolFileDWARF &GetBaseSymbolFile() const { return m_base_symbol_file; }
+
+ bool GetDebugInfoIndexWasLoadedFromCache() const override;
+ void SetDebugInfoIndexWasLoadedFromCache() override;
+ bool GetDebugInfoIndexWasSavedToCache() const override;
+ void SetDebugInfoIndexWasSavedToCache() override;
+ bool GetDebugInfoHadFrameVariableErrors() const override;
+ void SetDebugInfoHadFrameVariableErrors() override;
+
+ SymbolFileDWARF *GetDIERefSymbolFile(const DIERef &die_ref) override;
+
+protected:
+ DIEToTypePtr &GetDIEToType() override;
+
+ DIEToVariableSP &GetDIEToVariable() override;
+
+ llvm::DenseMap<lldb::opaque_compiler_type_t, DIERef> &
+ GetForwardDeclCompilerTypeToDIE() override;
+
+ UniqueDWARFASTTypeMap &GetUniqueDWARFASTTypeMap() override;
+
+ DWARFDIE FindDefinitionDIE(const DWARFDIE &die) override;
+
+ lldb::TypeSP
+ FindCompleteObjCDefinitionTypeForDIE(const DWARFDIE &die,
+ ConstString type_name,
+ bool must_be_implementation) override;
+
+ /// If this file contains exactly one compile unit, this function will return
+ /// it. Otherwise it returns nullptr.
+ DWARFCompileUnit *FindSingleCompileUnit();
+
+ SymbolFileDWARF &m_base_symbol_file;
+};
+} // namespace dwarf
+} // namespace lldb_private::plugin
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_SYMBOLFILEDWARFDWO_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFProperties.td b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFProperties.td
new file mode 100644
index 000000000000..2f1ce88808b7
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFProperties.td
@@ -0,0 +1,8 @@
+include "../../../../include/lldb/Core/PropertiesBase.td"
+
+let Definition = "symbolfiledwarf" in {
+ def IgnoreIndexes: Property<"ignore-file-indexes", "Boolean">,
+ Global,
+ DefaultFalse,
+ Desc<"Ignore indexes present in the object files and always index DWARF manually.">;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp
new file mode 100644
index 000000000000..3d201e96f92c
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp
@@ -0,0 +1,87 @@
+//===-- UniqueDWARFASTType.cpp --------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "UniqueDWARFASTType.h"
+
+#include "lldb/Core/Declaration.h"
+
+using namespace lldb_private::dwarf;
+using namespace lldb_private::plugin::dwarf;
+
+static bool IsStructOrClassTag(llvm::dwarf::Tag Tag) {
+ return Tag == llvm::dwarf::Tag::DW_TAG_class_type ||
+ Tag == llvm::dwarf::Tag::DW_TAG_structure_type;
+}
+
+UniqueDWARFASTType *UniqueDWARFASTTypeList::Find(
+ const DWARFDIE &die, const lldb_private::Declaration &decl,
+ const int32_t byte_size, bool is_forward_declaration) {
+ for (UniqueDWARFASTType &udt : m_collection) {
+ // Make sure the tags match
+ if (udt.m_die.Tag() == die.Tag() || (IsStructOrClassTag(udt.m_die.Tag()) &&
+ IsStructOrClassTag(die.Tag()))) {
+ // If they are not both definition DIEs or both declaration DIEs, then
+ // don't check for byte size and declaration location, because declaration
+ // DIEs usually don't have those info.
+ bool matching_size_declaration =
+ udt.m_is_forward_declaration != is_forward_declaration
+ ? true
+ : (udt.m_byte_size < 0 || byte_size < 0 ||
+ udt.m_byte_size == byte_size) &&
+ udt.m_declaration == decl;
+ if (!matching_size_declaration)
+ continue;
+ // The type has the same name, and was defined on the same file and
+ // line. Now verify all of the parent DIEs match.
+ DWARFDIE parent_arg_die = die.GetParent();
+ DWARFDIE parent_pos_die = udt.m_die.GetParent();
+ bool match = true;
+ bool done = false;
+ while (!done && match && parent_arg_die && parent_pos_die) {
+ const dw_tag_t parent_arg_tag = parent_arg_die.Tag();
+ const dw_tag_t parent_pos_tag = parent_pos_die.Tag();
+ if (parent_arg_tag == parent_pos_tag ||
+ (IsStructOrClassTag(parent_arg_tag) &&
+ IsStructOrClassTag(parent_pos_tag))) {
+ switch (parent_arg_tag) {
+ case DW_TAG_class_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_namespace: {
+ const char *parent_arg_die_name = parent_arg_die.GetName();
+ if (parent_arg_die_name == nullptr) {
+ // Anonymous (i.e. no-name) struct
+ match = false;
+ } else {
+ const char *parent_pos_die_name = parent_pos_die.GetName();
+ if (parent_pos_die_name == nullptr ||
+ ((parent_arg_die_name != parent_pos_die_name) &&
+ strcmp(parent_arg_die_name, parent_pos_die_name)))
+ match = false;
+ }
+ } break;
+
+ case DW_TAG_compile_unit:
+ case DW_TAG_partial_unit:
+ done = true;
+ break;
+ default:
+ break;
+ }
+ }
+ parent_arg_die = parent_arg_die.GetParent();
+ parent_pos_die = parent_pos_die.GetParent();
+ }
+
+ if (match) {
+ return &udt;
+ }
+ }
+ }
+ return nullptr;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h
new file mode 100644
index 000000000000..9215484fa2ea
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h
@@ -0,0 +1,107 @@
+//===-- UniqueDWARFASTType.h ------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_UNIQUEDWARFASTTYPE_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_UNIQUEDWARFASTTYPE_H
+
+#include <vector>
+
+#include "llvm/ADT/DenseMap.h"
+
+#include "DWARFDIE.h"
+#include "lldb/Core/Declaration.h"
+#include "lldb/Symbol/Type.h"
+
+namespace lldb_private::plugin {
+namespace dwarf {
+class UniqueDWARFASTType {
+public:
+ // Constructors and Destructors
+ UniqueDWARFASTType() : m_type_sp(), m_die(), m_declaration() {}
+
+ UniqueDWARFASTType(const UniqueDWARFASTType &rhs)
+ : m_type_sp(rhs.m_type_sp), m_die(rhs.m_die),
+ m_declaration(rhs.m_declaration), m_byte_size(rhs.m_byte_size),
+ m_is_forward_declaration(rhs.m_is_forward_declaration) {}
+
+ ~UniqueDWARFASTType() = default;
+
+ // This UniqueDWARFASTType might be created from declaration, update its info
+ // to definition DIE.
+ void UpdateToDefDIE(const DWARFDIE &def_die, Declaration &declaration,
+ int32_t byte_size) {
+ // Need to update Type ID to refer to the definition DIE, because
+ // it's used in DWARFASTParserClang::ParseCXXMethod to determine if we need
+ // to copy cxx method types from a declaration DIE to this definition DIE.
+ m_type_sp->SetID(def_die.GetID());
+ if (declaration.IsValid())
+ m_declaration = declaration;
+ if (byte_size)
+ m_byte_size = byte_size;
+ m_is_forward_declaration = false;
+ }
+
+ lldb::TypeSP m_type_sp;
+ DWARFDIE m_die;
+ Declaration m_declaration;
+ int32_t m_byte_size = -1;
+ // True if the m_die is a forward declaration DIE.
+ bool m_is_forward_declaration = true;
+};
+
+class UniqueDWARFASTTypeList {
+public:
+ UniqueDWARFASTTypeList() : m_collection() {}
+
+ ~UniqueDWARFASTTypeList() = default;
+
+ uint32_t GetSize() { return (uint32_t)m_collection.size(); }
+
+ void Append(const UniqueDWARFASTType &entry) {
+ m_collection.push_back(entry);
+ }
+
+ UniqueDWARFASTType *Find(const DWARFDIE &die, const Declaration &decl,
+ const int32_t byte_size,
+ bool is_forward_declaration);
+
+protected:
+ typedef std::vector<UniqueDWARFASTType> collection;
+ collection m_collection;
+};
+
+class UniqueDWARFASTTypeMap {
+public:
+ UniqueDWARFASTTypeMap() : m_collection() {}
+
+ ~UniqueDWARFASTTypeMap() = default;
+
+ void Insert(ConstString name, const UniqueDWARFASTType &entry) {
+ m_collection[name.GetCString()].Append(entry);
+ }
+
+ UniqueDWARFASTType *Find(ConstString name, const DWARFDIE &die,
+ const Declaration &decl, const int32_t byte_size,
+ bool is_forward_declaration) {
+ const char *unique_name_cstr = name.GetCString();
+ collection::iterator pos = m_collection.find(unique_name_cstr);
+ if (pos != m_collection.end()) {
+ return pos->second.Find(die, decl, byte_size, is_forward_declaration);
+ }
+ return nullptr;
+ }
+
+protected:
+ // A unique name string should be used
+ typedef llvm::DenseMap<const char *, UniqueDWARFASTTypeList> collection;
+ collection m_collection;
+};
+} // namespace dwarf
+} // namespace lldb_private::plugin
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_UNIQUEDWARFASTTYPE_H