aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lldb/source/Plugins/SymbolFile
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/lldb/source/Plugins/SymbolFile')
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp924
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h235
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/CTF/CTFTypes.h203
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.cpp1118
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.h264
-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
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/JSON/SymbolFileJSON.cpp105
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/JSON/SymbolFileJSON.h110
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.cpp748
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.h25
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp248
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h108
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp300
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h57
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp1454
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h159
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.cpp103
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.h28
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp196
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.h159
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbSymUid.cpp160
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbSymUid.h125
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp1120
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h157
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp2336
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h286
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp501
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h146
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp1455
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.h116
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp182
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.h47
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp2053
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h252
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp258
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h103
96 files changed, 36737 insertions, 0 deletions
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp
new file mode 100644
index 000000000000..3977dc3a6d67
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp
@@ -0,0 +1,924 @@
+//===-- SymbolFileBreakpad.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/Breakpad/SymbolFileBreakpad.h"
+#include "Plugins/ObjectFile/Breakpad/BreakpadRecords.h"
+#include "Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Symbol/TypeMap.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
+#include "llvm/ADT/StringExtras.h"
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::breakpad;
+
+LLDB_PLUGIN_DEFINE(SymbolFileBreakpad)
+
+char SymbolFileBreakpad::ID;
+
+class SymbolFileBreakpad::LineIterator {
+public:
+ // begin iterator for sections of given type
+ LineIterator(ObjectFile &obj, Record::Kind section_type)
+ : m_obj(&obj), m_section_type(toString(section_type)),
+ m_next_section_idx(0), m_next_line(llvm::StringRef::npos) {
+ ++*this;
+ }
+
+ // An iterator starting at the position given by the bookmark.
+ LineIterator(ObjectFile &obj, Record::Kind section_type, Bookmark bookmark);
+
+ // end iterator
+ explicit LineIterator(ObjectFile &obj)
+ : m_obj(&obj),
+ m_next_section_idx(m_obj->GetSectionList()->GetNumSections(0)),
+ m_current_line(llvm::StringRef::npos),
+ m_next_line(llvm::StringRef::npos) {}
+
+ friend bool operator!=(const LineIterator &lhs, const LineIterator &rhs) {
+ assert(lhs.m_obj == rhs.m_obj);
+ if (lhs.m_next_section_idx != rhs.m_next_section_idx)
+ return true;
+ if (lhs.m_current_line != rhs.m_current_line)
+ return true;
+ assert(lhs.m_next_line == rhs.m_next_line);
+ return false;
+ }
+
+ const LineIterator &operator++();
+ llvm::StringRef operator*() const {
+ return m_section_text.slice(m_current_line, m_next_line);
+ }
+
+ Bookmark GetBookmark() const {
+ return Bookmark{m_next_section_idx, m_current_line};
+ }
+
+private:
+ ObjectFile *m_obj;
+ ConstString m_section_type;
+ uint32_t m_next_section_idx;
+ llvm::StringRef m_section_text;
+ size_t m_current_line;
+ size_t m_next_line;
+
+ void FindNextLine() {
+ m_next_line = m_section_text.find('\n', m_current_line);
+ if (m_next_line != llvm::StringRef::npos) {
+ ++m_next_line;
+ if (m_next_line >= m_section_text.size())
+ m_next_line = llvm::StringRef::npos;
+ }
+ }
+};
+
+SymbolFileBreakpad::LineIterator::LineIterator(ObjectFile &obj,
+ Record::Kind section_type,
+ Bookmark bookmark)
+ : m_obj(&obj), m_section_type(toString(section_type)),
+ m_next_section_idx(bookmark.section), m_current_line(bookmark.offset) {
+ Section &sect =
+ *obj.GetSectionList()->GetSectionAtIndex(m_next_section_idx - 1);
+ assert(sect.GetName() == m_section_type);
+
+ DataExtractor data;
+ obj.ReadSectionData(&sect, data);
+ m_section_text = toStringRef(data.GetData());
+
+ assert(m_current_line < m_section_text.size());
+ FindNextLine();
+}
+
+const SymbolFileBreakpad::LineIterator &
+SymbolFileBreakpad::LineIterator::operator++() {
+ const SectionList &list = *m_obj->GetSectionList();
+ size_t num_sections = list.GetNumSections(0);
+ while (m_next_line != llvm::StringRef::npos ||
+ m_next_section_idx < num_sections) {
+ if (m_next_line != llvm::StringRef::npos) {
+ m_current_line = m_next_line;
+ FindNextLine();
+ return *this;
+ }
+
+ Section &sect = *list.GetSectionAtIndex(m_next_section_idx++);
+ if (sect.GetName() != m_section_type)
+ continue;
+ DataExtractor data;
+ m_obj->ReadSectionData(&sect, data);
+ m_section_text = toStringRef(data.GetData());
+ m_next_line = 0;
+ }
+ // We've reached the end.
+ m_current_line = m_next_line;
+ return *this;
+}
+
+llvm::iterator_range<SymbolFileBreakpad::LineIterator>
+SymbolFileBreakpad::lines(Record::Kind section_type) {
+ return llvm::make_range(LineIterator(*m_objfile_sp, section_type),
+ LineIterator(*m_objfile_sp));
+}
+
+namespace {
+// A helper class for constructing the list of support files for a given compile
+// unit.
+class SupportFileMap {
+public:
+ // Given a breakpad file ID, return a file ID to be used in the support files
+ // for this compile unit.
+ size_t operator[](size_t file) {
+ return m_map.try_emplace(file, m_map.size() + 1).first->second;
+ }
+
+ // Construct a FileSpecList containing only the support files relevant for
+ // this compile unit (in the correct order).
+ FileSpecList translate(const FileSpec &cu_spec,
+ llvm::ArrayRef<FileSpec> all_files);
+
+private:
+ llvm::DenseMap<size_t, size_t> m_map;
+};
+} // namespace
+
+FileSpecList SupportFileMap::translate(const FileSpec &cu_spec,
+ llvm::ArrayRef<FileSpec> all_files) {
+ std::vector<FileSpec> result;
+ result.resize(m_map.size() + 1);
+ result[0] = cu_spec;
+ for (const auto &KV : m_map) {
+ if (KV.first < all_files.size())
+ result[KV.second] = all_files[KV.first];
+ }
+ return FileSpecList(std::move(result));
+}
+
+void SymbolFileBreakpad::Initialize() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(), CreateInstance,
+ DebuggerInitialize);
+}
+
+void SymbolFileBreakpad::Terminate() {
+ PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+uint32_t SymbolFileBreakpad::CalculateAbilities() {
+ if (!m_objfile_sp || !llvm::isa<ObjectFileBreakpad>(*m_objfile_sp))
+ return 0;
+
+ return CompileUnits | Functions | LineTables;
+}
+
+uint32_t SymbolFileBreakpad::CalculateNumCompileUnits() {
+ ParseCUData();
+ return m_cu_data->GetSize();
+}
+
+CompUnitSP SymbolFileBreakpad::ParseCompileUnitAtIndex(uint32_t index) {
+ if (index >= m_cu_data->GetSize())
+ return nullptr;
+
+ CompUnitData &data = m_cu_data->GetEntryRef(index).data;
+
+ ParseFileRecords();
+
+ FileSpec spec;
+
+ // The FileSpec of the compile unit will be the file corresponding to the
+ // first LINE record.
+ LineIterator It(*m_objfile_sp, Record::Func, data.bookmark),
+ End(*m_objfile_sp);
+ assert(Record::classify(*It) == Record::Func);
+ ++It; // Skip FUNC record.
+ // Skip INLINE records.
+ while (It != End && Record::classify(*It) == Record::Inline)
+ ++It;
+
+ if (It != End) {
+ auto record = LineRecord::parse(*It);
+ if (record && record->FileNum < m_files->size())
+ spec = (*m_files)[record->FileNum];
+ }
+
+ auto cu_sp = std::make_shared<CompileUnit>(
+ m_objfile_sp->GetModule(),
+ /*user_data*/ nullptr, std::make_shared<SupportFile>(spec), index,
+ eLanguageTypeUnknown,
+ /*is_optimized*/ eLazyBoolNo);
+
+ SetCompileUnitAtIndex(index, cu_sp);
+ return cu_sp;
+}
+
+FunctionSP SymbolFileBreakpad::GetOrCreateFunction(CompileUnit &comp_unit) {
+ user_id_t id = comp_unit.GetID();
+ if (FunctionSP func_sp = comp_unit.FindFunctionByUID(id))
+ return func_sp;
+
+ Log *log = GetLog(LLDBLog::Symbols);
+ FunctionSP func_sp;
+ addr_t base = GetBaseFileAddress();
+ if (base == LLDB_INVALID_ADDRESS) {
+ LLDB_LOG(log, "Unable to fetch the base address of object file. Skipping "
+ "symtab population.");
+ return func_sp;
+ }
+
+ const SectionList *list = comp_unit.GetModule()->GetSectionList();
+ CompUnitData &data = m_cu_data->GetEntryRef(id).data;
+ LineIterator It(*m_objfile_sp, Record::Func, data.bookmark);
+ assert(Record::classify(*It) == Record::Func);
+
+ if (auto record = FuncRecord::parse(*It)) {
+ Mangled func_name;
+ func_name.SetValue(ConstString(record->Name));
+ addr_t address = record->Address + base;
+ SectionSP section_sp = list->FindSectionContainingFileAddress(address);
+ if (section_sp) {
+ AddressRange func_range(
+ section_sp, address - section_sp->GetFileAddress(), record->Size);
+ // Use the CU's id because every CU has only one function inside.
+ func_sp = std::make_shared<Function>(&comp_unit, id, 0, func_name,
+ nullptr, func_range);
+ comp_unit.AddFunction(func_sp);
+ }
+ }
+ return func_sp;
+}
+
+size_t SymbolFileBreakpad::ParseFunctions(CompileUnit &comp_unit) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ return GetOrCreateFunction(comp_unit) ? 1 : 0;
+}
+
+bool SymbolFileBreakpad::ParseLineTable(CompileUnit &comp_unit) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ CompUnitData &data = m_cu_data->GetEntryRef(comp_unit.GetID()).data;
+
+ if (!data.line_table_up)
+ ParseLineTableAndSupportFiles(comp_unit, data);
+
+ comp_unit.SetLineTable(data.line_table_up.release());
+ return true;
+}
+
+bool SymbolFileBreakpad::ParseSupportFiles(CompileUnit &comp_unit,
+ SupportFileList &support_files) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ CompUnitData &data = m_cu_data->GetEntryRef(comp_unit.GetID()).data;
+ if (!data.support_files)
+ ParseLineTableAndSupportFiles(comp_unit, data);
+
+ for (auto &fs : *data.support_files)
+ support_files.Append(fs);
+ return true;
+}
+
+size_t SymbolFileBreakpad::ParseBlocksRecursive(Function &func) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ CompileUnit *comp_unit = func.GetCompileUnit();
+ lldbassert(comp_unit);
+ ParseInlineOriginRecords();
+ // A vector of current each level's parent block. For example, when parsing
+ // "INLINE 0 ...", the current level is 0 and its parent block is the
+ // function block at index 0.
+ std::vector<Block *> blocks;
+ Block &block = func.GetBlock(false);
+ block.AddRange(Block::Range(0, func.GetAddressRange().GetByteSize()));
+ blocks.push_back(&block);
+
+ size_t blocks_added = 0;
+ addr_t func_base = func.GetAddressRange().GetBaseAddress().GetOffset();
+ CompUnitData &data = m_cu_data->GetEntryRef(comp_unit->GetID()).data;
+ LineIterator It(*m_objfile_sp, Record::Func, data.bookmark),
+ End(*m_objfile_sp);
+ ++It; // Skip the FUNC record.
+ size_t last_added_nest_level = 0;
+ while (It != End && Record::classify(*It) == Record::Inline) {
+ if (auto record = InlineRecord::parse(*It)) {
+ if (record->InlineNestLevel == 0 ||
+ record->InlineNestLevel <= last_added_nest_level + 1) {
+ last_added_nest_level = record->InlineNestLevel;
+ BlockSP block_sp = std::make_shared<Block>(It.GetBookmark().offset);
+ FileSpec callsite_file;
+ if (record->CallSiteFileNum < m_files->size())
+ callsite_file = (*m_files)[record->CallSiteFileNum];
+ llvm::StringRef name;
+ if (record->OriginNum < m_inline_origins->size())
+ name = (*m_inline_origins)[record->OriginNum];
+
+ Declaration callsite(callsite_file, record->CallSiteLineNum);
+ block_sp->SetInlinedFunctionInfo(name.str().c_str(),
+ /*mangled=*/nullptr,
+ /*decl_ptr=*/nullptr, &callsite);
+ for (const auto &range : record->Ranges) {
+ block_sp->AddRange(
+ Block::Range(range.first - func_base, range.second));
+ }
+ block_sp->FinalizeRanges();
+
+ blocks[record->InlineNestLevel]->AddChild(block_sp);
+ if (record->InlineNestLevel + 1 >= blocks.size()) {
+ blocks.resize(blocks.size() + 1);
+ }
+ blocks[record->InlineNestLevel + 1] = block_sp.get();
+ ++blocks_added;
+ }
+ }
+ ++It;
+ }
+ return blocks_added;
+}
+
+void SymbolFileBreakpad::ParseInlineOriginRecords() {
+ if (m_inline_origins)
+ return;
+ m_inline_origins.emplace();
+
+ Log *log = GetLog(LLDBLog::Symbols);
+ for (llvm::StringRef line : lines(Record::InlineOrigin)) {
+ auto record = InlineOriginRecord::parse(line);
+ if (!record) {
+ LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", line);
+ continue;
+ }
+
+ if (record->Number >= m_inline_origins->size())
+ m_inline_origins->resize(record->Number + 1);
+ (*m_inline_origins)[record->Number] = record->Name;
+ }
+}
+
+uint32_t
+SymbolFileBreakpad::ResolveSymbolContext(const Address &so_addr,
+ SymbolContextItem resolve_scope,
+ SymbolContext &sc) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ if (!(resolve_scope & (eSymbolContextCompUnit | eSymbolContextLineEntry |
+ eSymbolContextFunction | eSymbolContextBlock)))
+ return 0;
+
+ ParseCUData();
+ uint32_t idx =
+ m_cu_data->FindEntryIndexThatContains(so_addr.GetFileAddress());
+ if (idx == UINT32_MAX)
+ return 0;
+
+ sc.comp_unit = GetCompileUnitAtIndex(idx).get();
+ SymbolContextItem result = eSymbolContextCompUnit;
+ if (resolve_scope & eSymbolContextLineEntry) {
+ if (sc.comp_unit->GetLineTable()->FindLineEntryByAddress(so_addr,
+ sc.line_entry)) {
+ result |= eSymbolContextLineEntry;
+ }
+ }
+
+ if (resolve_scope & (eSymbolContextFunction | eSymbolContextBlock)) {
+ FunctionSP func_sp = GetOrCreateFunction(*sc.comp_unit);
+ if (func_sp) {
+ sc.function = func_sp.get();
+ result |= eSymbolContextFunction;
+ if (resolve_scope & eSymbolContextBlock) {
+ Block &block = func_sp->GetBlock(true);
+ sc.block = block.FindInnermostBlockByOffset(
+ so_addr.GetFileAddress() -
+ sc.function->GetAddressRange().GetBaseAddress().GetFileAddress());
+ if (sc.block)
+ result |= eSymbolContextBlock;
+ }
+ }
+ }
+
+ return result;
+}
+
+uint32_t SymbolFileBreakpad::ResolveSymbolContext(
+ const SourceLocationSpec &src_location_spec,
+ lldb::SymbolContextItem resolve_scope, SymbolContextList &sc_list) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ if (!(resolve_scope & eSymbolContextCompUnit))
+ return 0;
+
+ uint32_t old_size = sc_list.GetSize();
+ for (size_t i = 0, size = GetNumCompileUnits(); i < size; ++i) {
+ CompileUnit &cu = *GetCompileUnitAtIndex(i);
+ cu.ResolveSymbolContext(src_location_spec, resolve_scope, sc_list);
+ }
+ return sc_list.GetSize() - old_size;
+}
+
+void SymbolFileBreakpad::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());
+ // TODO: Implement this with supported FunctionNameType.
+
+ ConstString name = lookup_info.GetLookupName();
+ for (uint32_t i = 0; i < GetNumCompileUnits(); ++i) {
+ CompUnitSP cu_sp = GetCompileUnitAtIndex(i);
+ FunctionSP func_sp = GetOrCreateFunction(*cu_sp);
+ if (func_sp && name == func_sp->GetNameNoArguments()) {
+ SymbolContext sc;
+ sc.comp_unit = cu_sp.get();
+ sc.function = func_sp.get();
+ sc.module_sp = func_sp->CalculateSymbolContextModule();
+ sc_list.Append(sc);
+ }
+ }
+}
+
+void SymbolFileBreakpad::FindFunctions(const RegularExpression &regex,
+ bool include_inlines,
+ SymbolContextList &sc_list) {
+ // TODO
+}
+
+void SymbolFileBreakpad::AddSymbols(Symtab &symtab) {
+ Log *log = GetLog(LLDBLog::Symbols);
+ Module &module = *m_objfile_sp->GetModule();
+ addr_t base = GetBaseFileAddress();
+ if (base == LLDB_INVALID_ADDRESS) {
+ LLDB_LOG(log, "Unable to fetch the base address of object file. Skipping "
+ "symtab population.");
+ return;
+ }
+
+ const SectionList &list = *module.GetSectionList();
+ llvm::DenseSet<addr_t> found_symbol_addresses;
+ std::vector<Symbol> symbols;
+ auto add_symbol = [&](addr_t address, std::optional<addr_t> size,
+ llvm::StringRef name) {
+ address += base;
+ SectionSP section_sp = list.FindSectionContainingFileAddress(address);
+ if (!section_sp) {
+ LLDB_LOG(log,
+ "Ignoring symbol {0}, whose address ({1}) is outside of the "
+ "object file. Mismatched symbol file?",
+ name, address);
+ return;
+ }
+ // Keep track of what addresses were already added so far and only add
+ // the symbol with the first address.
+ if (!found_symbol_addresses.insert(address).second)
+ return;
+ symbols.emplace_back(
+ /*symID*/ 0, Mangled(name), eSymbolTypeCode,
+ /*is_global*/ true, /*is_debug*/ false,
+ /*is_trampoline*/ false, /*is_artificial*/ false,
+ AddressRange(section_sp, address - section_sp->GetFileAddress(),
+ size.value_or(0)),
+ size.has_value(), /*contains_linker_annotations*/ false, /*flags*/ 0);
+ };
+
+ for (llvm::StringRef line : lines(Record::Public)) {
+ if (auto record = PublicRecord::parse(line))
+ add_symbol(record->Address, std::nullopt, record->Name);
+ else
+ LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", line);
+ }
+
+ for (Symbol &symbol : symbols)
+ symtab.AddSymbol(std::move(symbol));
+ symtab.Finalize();
+}
+
+llvm::Expected<lldb::addr_t>
+SymbolFileBreakpad::GetParameterStackSize(Symbol &symbol) {
+ ParseUnwindData();
+ if (auto *entry = m_unwind_data->win.FindEntryThatContains(
+ symbol.GetAddress().GetFileAddress())) {
+ auto record = StackWinRecord::parse(
+ *LineIterator(*m_objfile_sp, Record::StackWin, entry->data));
+ assert(record);
+ return record->ParameterSize;
+ }
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Parameter size unknown.");
+}
+
+static std::optional<std::pair<llvm::StringRef, llvm::StringRef>>
+GetRule(llvm::StringRef &unwind_rules) {
+ // Unwind rules are of the form
+ // register1: expression1 register2: expression2 ...
+ // We assume none of the tokens in expression<n> end with a colon.
+
+ llvm::StringRef lhs, rest;
+ std::tie(lhs, rest) = getToken(unwind_rules);
+ if (!lhs.consume_back(":"))
+ return std::nullopt;
+
+ // Seek forward to the next register: expression pair
+ llvm::StringRef::size_type pos = rest.find(": ");
+ if (pos == llvm::StringRef::npos) {
+ // No pair found, this means the rest of the string is a single expression.
+ unwind_rules = llvm::StringRef();
+ return std::make_pair(lhs, rest);
+ }
+
+ // Go back one token to find the end of the current rule.
+ pos = rest.rfind(' ', pos);
+ if (pos == llvm::StringRef::npos)
+ return std::nullopt;
+
+ llvm::StringRef rhs = rest.take_front(pos);
+ unwind_rules = rest.drop_front(pos);
+ return std::make_pair(lhs, rhs);
+}
+
+static const RegisterInfo *
+ResolveRegister(const llvm::Triple &triple,
+ const SymbolFile::RegisterInfoResolver &resolver,
+ llvm::StringRef name) {
+ if (triple.isX86() || triple.isMIPS()) {
+ // X86 and MIPS registers have '$' in front of their register names. Arm and
+ // AArch64 don't.
+ if (!name.consume_front("$"))
+ return nullptr;
+ }
+ return resolver.ResolveName(name);
+}
+
+static const RegisterInfo *
+ResolveRegisterOrRA(const llvm::Triple &triple,
+ const SymbolFile::RegisterInfoResolver &resolver,
+ llvm::StringRef name) {
+ if (name == ".ra")
+ return resolver.ResolveNumber(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ return ResolveRegister(triple, resolver, name);
+}
+
+llvm::ArrayRef<uint8_t> SymbolFileBreakpad::SaveAsDWARF(postfix::Node &node) {
+ ArchSpec arch = m_objfile_sp->GetArchitecture();
+ StreamString dwarf(Stream::eBinary, arch.GetAddressByteSize(),
+ arch.GetByteOrder());
+ ToDWARF(node, dwarf);
+ uint8_t *saved = m_allocator.Allocate<uint8_t>(dwarf.GetSize());
+ std::memcpy(saved, dwarf.GetData(), dwarf.GetSize());
+ return {saved, dwarf.GetSize()};
+}
+
+bool SymbolFileBreakpad::ParseCFIUnwindRow(llvm::StringRef unwind_rules,
+ const RegisterInfoResolver &resolver,
+ UnwindPlan::Row &row) {
+ Log *log = GetLog(LLDBLog::Symbols);
+
+ llvm::BumpPtrAllocator node_alloc;
+ llvm::Triple triple = m_objfile_sp->GetArchitecture().GetTriple();
+ while (auto rule = GetRule(unwind_rules)) {
+ node_alloc.Reset();
+ llvm::StringRef lhs = rule->first;
+ postfix::Node *rhs = postfix::ParseOneExpression(rule->second, node_alloc);
+ if (!rhs) {
+ LLDB_LOG(log, "Could not parse `{0}` as unwind rhs.", rule->second);
+ return false;
+ }
+
+ bool success = postfix::ResolveSymbols(
+ rhs, [&](postfix::SymbolNode &symbol) -> postfix::Node * {
+ llvm::StringRef name = symbol.GetName();
+ if (name == ".cfa" && lhs != ".cfa")
+ return postfix::MakeNode<postfix::InitialValueNode>(node_alloc);
+
+ if (const RegisterInfo *info =
+ ResolveRegister(triple, resolver, name)) {
+ return postfix::MakeNode<postfix::RegisterNode>(
+ node_alloc, info->kinds[eRegisterKindLLDB]);
+ }
+ return nullptr;
+ });
+
+ if (!success) {
+ LLDB_LOG(log, "Resolving symbols in `{0}` failed.", rule->second);
+ return false;
+ }
+
+ llvm::ArrayRef<uint8_t> saved = SaveAsDWARF(*rhs);
+ if (lhs == ".cfa") {
+ row.GetCFAValue().SetIsDWARFExpression(saved.data(), saved.size());
+ } else if (const RegisterInfo *info =
+ ResolveRegisterOrRA(triple, resolver, lhs)) {
+ UnwindPlan::Row::RegisterLocation loc;
+ loc.SetIsDWARFExpression(saved.data(), saved.size());
+ row.SetRegisterInfo(info->kinds[eRegisterKindLLDB], loc);
+ } else
+ LLDB_LOG(log, "Invalid register `{0}` in unwind rule.", lhs);
+ }
+ if (unwind_rules.empty())
+ return true;
+
+ LLDB_LOG(log, "Could not parse `{0}` as an unwind rule.", unwind_rules);
+ return false;
+}
+
+UnwindPlanSP
+SymbolFileBreakpad::GetUnwindPlan(const Address &address,
+ const RegisterInfoResolver &resolver) {
+ ParseUnwindData();
+ if (auto *entry =
+ m_unwind_data->cfi.FindEntryThatContains(address.GetFileAddress()))
+ return ParseCFIUnwindPlan(entry->data, resolver);
+ if (auto *entry =
+ m_unwind_data->win.FindEntryThatContains(address.GetFileAddress()))
+ return ParseWinUnwindPlan(entry->data, resolver);
+ return nullptr;
+}
+
+UnwindPlanSP
+SymbolFileBreakpad::ParseCFIUnwindPlan(const Bookmark &bookmark,
+ const RegisterInfoResolver &resolver) {
+ addr_t base = GetBaseFileAddress();
+ if (base == LLDB_INVALID_ADDRESS)
+ return nullptr;
+
+ LineIterator It(*m_objfile_sp, Record::StackCFI, bookmark),
+ End(*m_objfile_sp);
+ std::optional<StackCFIRecord> init_record = StackCFIRecord::parse(*It);
+ assert(init_record && init_record->Size &&
+ "Record already parsed successfully in ParseUnwindData!");
+
+ auto plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindLLDB);
+ plan_sp->SetSourceName("breakpad STACK CFI");
+ plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
+ plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo);
+ plan_sp->SetSourcedFromCompiler(eLazyBoolYes);
+ plan_sp->SetPlanValidAddressRange(
+ AddressRange(base + init_record->Address, *init_record->Size,
+ m_objfile_sp->GetModule()->GetSectionList()));
+
+ auto row_sp = std::make_shared<UnwindPlan::Row>();
+ row_sp->SetOffset(0);
+ if (!ParseCFIUnwindRow(init_record->UnwindRules, resolver, *row_sp))
+ return nullptr;
+ plan_sp->AppendRow(row_sp);
+ for (++It; It != End; ++It) {
+ std::optional<StackCFIRecord> record = StackCFIRecord::parse(*It);
+ if (!record)
+ return nullptr;
+ if (record->Size)
+ break;
+
+ row_sp = std::make_shared<UnwindPlan::Row>(*row_sp);
+ row_sp->SetOffset(record->Address - init_record->Address);
+ if (!ParseCFIUnwindRow(record->UnwindRules, resolver, *row_sp))
+ return nullptr;
+ plan_sp->AppendRow(row_sp);
+ }
+ return plan_sp;
+}
+
+UnwindPlanSP
+SymbolFileBreakpad::ParseWinUnwindPlan(const Bookmark &bookmark,
+ const RegisterInfoResolver &resolver) {
+ Log *log = GetLog(LLDBLog::Symbols);
+ addr_t base = GetBaseFileAddress();
+ if (base == LLDB_INVALID_ADDRESS)
+ return nullptr;
+
+ LineIterator It(*m_objfile_sp, Record::StackWin, bookmark);
+ std::optional<StackWinRecord> record = StackWinRecord::parse(*It);
+ assert(record && "Record already parsed successfully in ParseUnwindData!");
+
+ auto plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindLLDB);
+ plan_sp->SetSourceName("breakpad STACK WIN");
+ plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
+ plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo);
+ plan_sp->SetSourcedFromCompiler(eLazyBoolYes);
+ plan_sp->SetPlanValidAddressRange(
+ AddressRange(base + record->RVA, record->CodeSize,
+ m_objfile_sp->GetModule()->GetSectionList()));
+
+ auto row_sp = std::make_shared<UnwindPlan::Row>();
+ row_sp->SetOffset(0);
+
+ llvm::BumpPtrAllocator node_alloc;
+ std::vector<std::pair<llvm::StringRef, postfix::Node *>> program =
+ postfix::ParseFPOProgram(record->ProgramString, node_alloc);
+
+ if (program.empty()) {
+ LLDB_LOG(log, "Invalid unwind rule: {0}.", record->ProgramString);
+ return nullptr;
+ }
+ auto it = program.begin();
+ llvm::Triple triple = m_objfile_sp->GetArchitecture().GetTriple();
+ const auto &symbol_resolver =
+ [&](postfix::SymbolNode &symbol) -> postfix::Node * {
+ llvm::StringRef name = symbol.GetName();
+ for (const auto &rule : llvm::make_range(program.begin(), it)) {
+ if (rule.first == name)
+ return rule.second;
+ }
+ if (const RegisterInfo *info = ResolveRegister(triple, resolver, name))
+ return postfix::MakeNode<postfix::RegisterNode>(
+ node_alloc, info->kinds[eRegisterKindLLDB]);
+ return nullptr;
+ };
+
+ // We assume the first value will be the CFA. It is usually called T0, but
+ // clang will use T1, if it needs to realign the stack.
+ auto *symbol = llvm::dyn_cast<postfix::SymbolNode>(it->second);
+ if (symbol && symbol->GetName() == ".raSearch") {
+ row_sp->GetCFAValue().SetRaSearch(record->LocalSize +
+ record->SavedRegisterSize);
+ } else {
+ if (!postfix::ResolveSymbols(it->second, symbol_resolver)) {
+ LLDB_LOG(log, "Resolving symbols in `{0}` failed.",
+ record->ProgramString);
+ return nullptr;
+ }
+ llvm::ArrayRef<uint8_t> saved = SaveAsDWARF(*it->second);
+ row_sp->GetCFAValue().SetIsDWARFExpression(saved.data(), saved.size());
+ }
+
+ // Replace the node value with InitialValueNode, so that subsequent
+ // expressions refer to the CFA value instead of recomputing the whole
+ // expression.
+ it->second = postfix::MakeNode<postfix::InitialValueNode>(node_alloc);
+
+
+ // Now process the rest of the assignments.
+ for (++it; it != program.end(); ++it) {
+ const RegisterInfo *info = ResolveRegister(triple, resolver, it->first);
+ // It is not an error if the resolution fails because the program may
+ // contain temporary variables.
+ if (!info)
+ continue;
+ if (!postfix::ResolveSymbols(it->second, symbol_resolver)) {
+ LLDB_LOG(log, "Resolving symbols in `{0}` failed.",
+ record->ProgramString);
+ return nullptr;
+ }
+
+ llvm::ArrayRef<uint8_t> saved = SaveAsDWARF(*it->second);
+ UnwindPlan::Row::RegisterLocation loc;
+ loc.SetIsDWARFExpression(saved.data(), saved.size());
+ row_sp->SetRegisterInfo(info->kinds[eRegisterKindLLDB], loc);
+ }
+
+ plan_sp->AppendRow(row_sp);
+ return plan_sp;
+}
+
+addr_t SymbolFileBreakpad::GetBaseFileAddress() {
+ return m_objfile_sp->GetModule()
+ ->GetObjectFile()
+ ->GetBaseAddress()
+ .GetFileAddress();
+}
+
+// Parse out all the FILE records from the breakpad file. These will be needed
+// when constructing the support file lists for individual compile units.
+void SymbolFileBreakpad::ParseFileRecords() {
+ if (m_files)
+ return;
+ m_files.emplace();
+
+ Log *log = GetLog(LLDBLog::Symbols);
+ for (llvm::StringRef line : lines(Record::File)) {
+ auto record = FileRecord::parse(line);
+ if (!record) {
+ LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", line);
+ continue;
+ }
+
+ if (record->Number >= m_files->size())
+ m_files->resize(record->Number + 1);
+ FileSpec::Style style = FileSpec::GuessPathStyle(record->Name)
+ .value_or(FileSpec::Style::native);
+ (*m_files)[record->Number] = FileSpec(record->Name, style);
+ }
+}
+
+void SymbolFileBreakpad::ParseCUData() {
+ if (m_cu_data)
+ return;
+
+ m_cu_data.emplace();
+ Log *log = GetLog(LLDBLog::Symbols);
+ addr_t base = GetBaseFileAddress();
+ if (base == LLDB_INVALID_ADDRESS) {
+ LLDB_LOG(log, "SymbolFile parsing failed: Unable to fetch the base address "
+ "of object file.");
+ }
+
+ // We shall create one compile unit for each FUNC record. So, count the number
+ // of FUNC records, and store them in m_cu_data, together with their ranges.
+ for (LineIterator It(*m_objfile_sp, Record::Func), End(*m_objfile_sp);
+ It != End; ++It) {
+ if (auto record = FuncRecord::parse(*It)) {
+ m_cu_data->Append(CompUnitMap::Entry(base + record->Address, record->Size,
+ CompUnitData(It.GetBookmark())));
+ } else
+ LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", *It);
+ }
+ m_cu_data->Sort();
+}
+
+// Construct the list of support files and line table entries for the given
+// compile unit.
+void SymbolFileBreakpad::ParseLineTableAndSupportFiles(CompileUnit &cu,
+ CompUnitData &data) {
+ addr_t base = GetBaseFileAddress();
+ assert(base != LLDB_INVALID_ADDRESS &&
+ "How did we create compile units without a base address?");
+
+ SupportFileMap map;
+ std::vector<std::unique_ptr<LineSequence>> sequences;
+ std::unique_ptr<LineSequence> line_seq_up =
+ LineTable::CreateLineSequenceContainer();
+ std::optional<addr_t> next_addr;
+ auto finish_sequence = [&]() {
+ LineTable::AppendLineEntryToSequence(
+ line_seq_up.get(), *next_addr, /*line=*/0, /*column=*/0,
+ /*file_idx=*/0, /*is_start_of_statement=*/false,
+ /*is_start_of_basic_block=*/false, /*is_prologue_end=*/false,
+ /*is_epilogue_begin=*/false, /*is_terminal_entry=*/true);
+ sequences.push_back(std::move(line_seq_up));
+ line_seq_up = LineTable::CreateLineSequenceContainer();
+ };
+
+ LineIterator It(*m_objfile_sp, Record::Func, data.bookmark),
+ End(*m_objfile_sp);
+ assert(Record::classify(*It) == Record::Func);
+ for (++It; It != End; ++It) {
+ // Skip INLINE records
+ if (Record::classify(*It) == Record::Inline)
+ continue;
+
+ auto record = LineRecord::parse(*It);
+ if (!record)
+ break;
+
+ record->Address += base;
+
+ if (next_addr && *next_addr != record->Address) {
+ // Discontiguous entries. Finish off the previous sequence and reset.
+ finish_sequence();
+ }
+ LineTable::AppendLineEntryToSequence(
+ line_seq_up.get(), record->Address, record->LineNum, /*column=*/0,
+ map[record->FileNum], /*is_start_of_statement=*/true,
+ /*is_start_of_basic_block=*/false, /*is_prologue_end=*/false,
+ /*is_epilogue_begin=*/false, /*is_terminal_entry=*/false);
+ next_addr = record->Address + record->Size;
+ }
+ if (next_addr)
+ finish_sequence();
+ data.line_table_up = std::make_unique<LineTable>(&cu, std::move(sequences));
+ data.support_files = map.translate(cu.GetPrimaryFile(), *m_files);
+}
+
+void SymbolFileBreakpad::ParseUnwindData() {
+ if (m_unwind_data)
+ return;
+ m_unwind_data.emplace();
+
+ Log *log = GetLog(LLDBLog::Symbols);
+ addr_t base = GetBaseFileAddress();
+ if (base == LLDB_INVALID_ADDRESS) {
+ LLDB_LOG(log, "SymbolFile parsing failed: Unable to fetch the base address "
+ "of object file.");
+ }
+
+ for (LineIterator It(*m_objfile_sp, Record::StackCFI), End(*m_objfile_sp);
+ It != End; ++It) {
+ if (auto record = StackCFIRecord::parse(*It)) {
+ if (record->Size)
+ m_unwind_data->cfi.Append(UnwindMap::Entry(
+ base + record->Address, *record->Size, It.GetBookmark()));
+ } else
+ LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", *It);
+ }
+ m_unwind_data->cfi.Sort();
+
+ for (LineIterator It(*m_objfile_sp, Record::StackWin), End(*m_objfile_sp);
+ It != End; ++It) {
+ if (auto record = StackWinRecord::parse(*It)) {
+ m_unwind_data->win.Append(UnwindMap::Entry(
+ base + record->RVA, record->CodeSize, It.GetBookmark()));
+ } else
+ LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", *It);
+ }
+ m_unwind_data->win.Sort();
+}
+
+uint64_t SymbolFileBreakpad::GetDebugInfoSize(bool load_all_debug_info) {
+ // Breakpad files are all debug info.
+ return m_objfile_sp->GetByteSize();
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h
new file mode 100644
index 000000000000..041b388f9f34
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h
@@ -0,0 +1,235 @@
+//===-- SymbolFileBreakpad.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_BREAKPAD_SYMBOLFILEBREAKPAD_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_BREAKPAD_SYMBOLFILEBREAKPAD_H
+
+#include "Plugins/ObjectFile/Breakpad/BreakpadRecords.h"
+#include "lldb/Symbol/LineTable.h"
+#include "lldb/Symbol/PostfixExpression.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Utility/FileSpecList.h"
+#include <optional>
+
+namespace lldb_private {
+
+namespace breakpad {
+
+class SymbolFileBreakpad : 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 void DebuggerInitialize(Debugger &debugger) {}
+ static llvm::StringRef GetPluginNameStatic() { return "breakpad"; }
+
+ static llvm::StringRef GetPluginDescriptionStatic() {
+ return "Breakpad debug symbol file reader.";
+ }
+
+ static SymbolFile *CreateInstance(lldb::ObjectFileSP objfile_sp) {
+ return new SymbolFileBreakpad(std::move(objfile_sp));
+ }
+
+ // Constructors and Destructors
+ SymbolFileBreakpad(lldb::ObjectFileSP objfile_sp)
+ : SymbolFileCommon(std::move(objfile_sp)) {}
+
+ ~SymbolFileBreakpad() override = default;
+
+ uint32_t CalculateAbilities() override;
+
+ void InitializeObject() override {}
+
+ // Compile Unit function calls
+
+ lldb::LanguageType ParseLanguage(CompileUnit &comp_unit) override {
+ return lldb::eLanguageTypeUnknown;
+ }
+
+ lldb::FunctionSP GetOrCreateFunction(CompileUnit &comp_unit);
+
+ size_t ParseFunctions(CompileUnit &comp_unit) override;
+
+ bool ParseLineTable(CompileUnit &comp_unit) override;
+
+ bool ParseDebugMacros(CompileUnit &comp_unit) override { return false; }
+
+ bool ParseSupportFiles(CompileUnit &comp_unit,
+ SupportFileList &support_files) override;
+ size_t ParseTypes(CompileUnit &cu) override { return 0; }
+
+ bool ParseImportedModules(
+ const SymbolContext &sc,
+ std::vector<lldb_private::SourceModule> &imported_modules) override {
+ return false;
+ }
+
+ size_t ParseBlocksRecursive(Function &func) override;
+
+ void FindGlobalVariables(ConstString name,
+ const CompilerDeclContext &parent_decl_ctx,
+ uint32_t max_matches,
+ VariableList &variables) override {}
+
+ size_t ParseVariablesForContext(const SymbolContext &sc) override {
+ return 0;
+ }
+ Type *ResolveTypeUID(lldb::user_id_t type_uid) override { return nullptr; }
+ std::optional<ArrayInfo> GetDynamicArrayInfoForUID(
+ lldb::user_id_t type_uid,
+ const lldb_private::ExecutionContext *exe_ctx) override {
+ return std::nullopt;
+ }
+
+ bool CompleteType(CompilerType &compiler_type) override { return false; }
+ 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;
+
+ void GetTypes(SymbolContextScope *sc_scope, lldb::TypeClass type_mask,
+ TypeList &type_list) 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;
+
+ llvm::Expected<lldb::TypeSystemSP>
+ GetTypeSystemForLanguage(lldb::LanguageType language) override {
+ return llvm::createStringError(
+ "SymbolFileBreakpad does not support GetTypeSystemForLanguage");
+ }
+
+ CompilerDeclContext FindNamespace(ConstString name,
+ const CompilerDeclContext &parent_decl_ctx,
+ bool only_root_namespaces) override {
+ return CompilerDeclContext();
+ }
+
+ void AddSymbols(Symtab &symtab) override;
+
+ llvm::Expected<lldb::addr_t> GetParameterStackSize(Symbol &symbol) override;
+
+ lldb::UnwindPlanSP
+ GetUnwindPlan(const Address &address,
+ const RegisterInfoResolver &resolver) override;
+
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+ uint64_t GetDebugInfoSize(bool load_all_debug_info = false) override;
+
+private:
+ // A class representing a position in the breakpad file. Useful for
+ // remembering the position so we can go back to it later and parse more data.
+ // Can be converted to/from a LineIterator, but it has a much smaller memory
+ // footprint.
+ struct Bookmark {
+ uint32_t section;
+ size_t offset;
+
+ friend bool operator<(const Bookmark &lhs, const Bookmark &rhs) {
+ return std::tie(lhs.section, lhs.offset) <
+ std::tie(rhs.section, rhs.offset);
+ }
+ };
+
+ // At iterator class for simplifying algorithms reading data from the breakpad
+ // file. It iterates over all records (lines) in the sections of a given type.
+ // It also supports saving a specific position (via the GetBookmark() method)
+ // and then resuming from it afterwards.
+ class LineIterator;
+
+ // Return an iterator range for all records in the given object file of the
+ // given type.
+ llvm::iterator_range<LineIterator> lines(Record::Kind section_type);
+
+ // Breakpad files do not contain sufficient information to correctly
+ // reconstruct compile units. The approach chosen here is to treat each
+ // function as a compile unit. The compile unit name is the name if the first
+ // line entry belonging to this function.
+ // This class is our internal representation of a compile unit. It stores the
+ // CompileUnit object and a bookmark pointing to the FUNC record of the
+ // compile unit function. It also lazily construct the list of support files
+ // and line table entries for the compile unit, when these are needed.
+ class CompUnitData {
+ public:
+ CompUnitData(Bookmark bookmark) : bookmark(bookmark) {}
+
+ CompUnitData() = default;
+ CompUnitData(const CompUnitData &rhs) : bookmark(rhs.bookmark) {}
+ CompUnitData &operator=(const CompUnitData &rhs) {
+ bookmark = rhs.bookmark;
+ support_files.reset();
+ line_table_up.reset();
+ return *this;
+ }
+ friend bool operator<(const CompUnitData &lhs, const CompUnitData &rhs) {
+ return lhs.bookmark < rhs.bookmark;
+ }
+
+ Bookmark bookmark;
+ std::optional<FileSpecList> support_files;
+ std::unique_ptr<LineTable> line_table_up;
+ };
+
+ uint32_t CalculateNumCompileUnits() override;
+ lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index) override;
+
+ lldb::addr_t GetBaseFileAddress();
+ void ParseFileRecords();
+ void ParseCUData();
+ void ParseLineTableAndSupportFiles(CompileUnit &cu, CompUnitData &data);
+ void ParseUnwindData();
+ llvm::ArrayRef<uint8_t> SaveAsDWARF(postfix::Node &node);
+ lldb::UnwindPlanSP ParseCFIUnwindPlan(const Bookmark &bookmark,
+ const RegisterInfoResolver &resolver);
+ bool ParseCFIUnwindRow(llvm::StringRef unwind_rules,
+ const RegisterInfoResolver &resolver,
+ UnwindPlan::Row &row);
+ lldb::UnwindPlanSP ParseWinUnwindPlan(const Bookmark &bookmark,
+ const RegisterInfoResolver &resolver);
+ void ParseInlineOriginRecords();
+
+ using CompUnitMap = RangeDataVector<lldb::addr_t, lldb::addr_t, CompUnitData>;
+
+ std::optional<std::vector<FileSpec>> m_files;
+ std::optional<CompUnitMap> m_cu_data;
+ std::optional<std::vector<llvm::StringRef>> m_inline_origins;
+
+ using UnwindMap = RangeDataVector<lldb::addr_t, lldb::addr_t, Bookmark>;
+ struct UnwindData {
+ UnwindMap cfi;
+ UnwindMap win;
+ };
+ std::optional<UnwindData> m_unwind_data;
+ llvm::BumpPtrAllocator m_allocator;
+};
+
+} // namespace breakpad
+} // namespace lldb_private
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/CTF/CTFTypes.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/CTF/CTFTypes.h
new file mode 100644
index 000000000000..c1016b2af0c6
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/CTF/CTFTypes.h
@@ -0,0 +1,203 @@
+//===-- CTFTypes.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_CTF_CTFTYPES_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_CTF_CTFTYPES_H
+
+#include "lldb/lldb-types.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace lldb_private {
+
+struct CTFType {
+ enum Kind : uint32_t {
+ eUnknown = 0,
+ eInteger = 1,
+ eFloat = 2,
+ ePointer = 3,
+ eArray = 4,
+ eFunction = 5,
+ eStruct = 6,
+ eUnion = 7,
+ eEnum = 8,
+ eForward = 9,
+ eTypedef = 10,
+ eVolatile = 11,
+ eConst = 12,
+ eRestrict = 13,
+ eSlice = 14,
+ };
+
+ Kind kind;
+ lldb::user_id_t uid;
+ llvm::StringRef name;
+
+ CTFType(Kind kind, lldb::user_id_t uid, llvm::StringRef name)
+ : kind(kind), uid(uid), name(name) {}
+};
+
+struct CTFInteger : public CTFType {
+ CTFInteger(lldb::user_id_t uid, llvm::StringRef name, uint32_t bits,
+ uint32_t encoding)
+ : CTFType(eInteger, uid, name), bits(bits), encoding(encoding) {}
+
+ static bool classof(const CTFType *T) { return T->kind == eInteger; }
+
+ uint32_t bits;
+ uint32_t encoding;
+};
+
+struct CTFModifier : public CTFType {
+protected:
+ CTFModifier(Kind kind, lldb::user_id_t uid, uint32_t type)
+ : CTFType(kind, uid, ""), type(type) {}
+
+ static bool classof(const CTFType *T) {
+ return T->kind == ePointer || T->kind == eConst || T->kind == eVolatile ||
+ T->kind == eRestrict;
+ }
+
+public:
+ uint32_t type;
+};
+
+struct CTFPointer : public CTFModifier {
+ CTFPointer(lldb::user_id_t uid, uint32_t type)
+ : CTFModifier(ePointer, uid, type) {}
+
+ static bool classof(const CTFType *T) { return T->kind == ePointer; }
+};
+
+struct CTFConst : public CTFModifier {
+ CTFConst(lldb::user_id_t uid, uint32_t type)
+ : CTFModifier(eConst, uid, type) {}
+
+ static bool classof(const CTFType *T) { return T->kind == eConst; }
+};
+
+struct CTFVolatile : public CTFModifier {
+ CTFVolatile(lldb::user_id_t uid, uint32_t type)
+ : CTFModifier(eVolatile, uid, type) {}
+
+ static bool classof(const CTFType *T) { return T->kind == eVolatile; }
+};
+
+struct CTFRestrict : public CTFModifier {
+ CTFRestrict(lldb::user_id_t uid, uint32_t type)
+ : CTFModifier(eRestrict, uid, type) {}
+ static bool classof(const CTFType *T) { return T->kind == eRestrict; }
+};
+
+struct CTFTypedef : public CTFType {
+ CTFTypedef(lldb::user_id_t uid, llvm::StringRef name, uint32_t type)
+ : CTFType(eTypedef, uid, name), type(type) {}
+
+ static bool classof(const CTFType *T) { return T->kind == eTypedef; }
+
+ uint32_t type;
+};
+
+struct CTFArray : public CTFType {
+ CTFArray(lldb::user_id_t uid, llvm::StringRef name, uint32_t type,
+ uint32_t index, uint32_t nelems)
+ : CTFType(eArray, uid, name), type(type), index(index), nelems(nelems) {}
+
+ static bool classof(const CTFType *T) { return T->kind == eArray; }
+
+ uint32_t type;
+ uint32_t index;
+ uint32_t nelems;
+};
+
+struct CTFEnum : public CTFType {
+ struct Value {
+ Value(llvm::StringRef name, uint32_t value) : name(name), value(value){};
+ llvm::StringRef name;
+ uint32_t value;
+ };
+
+ CTFEnum(lldb::user_id_t uid, llvm::StringRef name, uint32_t nelems,
+ uint32_t size, std::vector<Value> values)
+ : CTFType(eEnum, uid, name), nelems(nelems), size(size),
+ values(std::move(values)) {
+ assert(this->values.size() == nelems);
+ }
+
+ static bool classof(const CTFType *T) { return T->kind == eEnum; }
+
+ uint32_t nelems;
+ uint32_t size;
+ std::vector<Value> values;
+};
+
+struct CTFFunction : public CTFType {
+ CTFFunction(lldb::user_id_t uid, llvm::StringRef name, uint32_t nargs,
+ uint32_t return_type, std::vector<uint32_t> args, bool variadic)
+ : CTFType(eFunction, uid, name), nargs(nargs), return_type(return_type),
+ args(std::move(args)), variadic(variadic) {}
+
+ static bool classof(const CTFType *T) { return T->kind == eFunction; }
+
+ uint32_t nargs;
+ uint32_t return_type;
+
+ std::vector<uint32_t> args;
+ bool variadic = false;
+};
+
+struct CTFRecord : public CTFType {
+public:
+ struct Field {
+ Field(llvm::StringRef name, uint32_t type, uint64_t offset)
+ : name(name), type(type), offset(offset) {}
+
+ llvm::StringRef name;
+ uint32_t type;
+ uint64_t offset;
+ };
+
+ CTFRecord(Kind kind, lldb::user_id_t uid, llvm::StringRef name,
+ uint32_t nfields, uint32_t size, std::vector<Field> fields)
+ : CTFType(kind, uid, name), nfields(nfields), size(size),
+ fields(std::move(fields)) {}
+
+ static bool classof(const CTFType *T) {
+ return T->kind == eStruct || T->kind == eUnion;
+ }
+
+ uint32_t nfields;
+ uint32_t size;
+ std::vector<Field> fields;
+};
+
+struct CTFStruct : public CTFRecord {
+ CTFStruct(lldb::user_id_t uid, llvm::StringRef name, uint32_t nfields,
+ uint32_t size, std::vector<Field> fields)
+ : CTFRecord(eStruct, uid, name, nfields, size, std::move(fields)){};
+
+ static bool classof(const CTFType *T) { return T->kind == eStruct; }
+};
+
+struct CTFUnion : public CTFRecord {
+ CTFUnion(lldb::user_id_t uid, llvm::StringRef name, uint32_t nfields,
+ uint32_t size, std::vector<Field> fields)
+ : CTFRecord(eUnion, uid, name, nfields, size, std::move(fields)){};
+
+ static bool classof(const CTFType *T) { return T->kind == eUnion; }
+};
+
+struct CTFForward : public CTFType {
+ CTFForward(lldb::user_id_t uid, llvm::StringRef name)
+ : CTFType(eForward, uid, name) {}
+
+ static bool classof(const CTFType *T) { return T->kind == eForward; }
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_CTF_CTFTYPES_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.cpp
new file mode 100644
index 000000000000..386ba44c5ea6
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.cpp
@@ -0,0 +1,1118 @@
+//===-- SymbolFileCTF.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 "SymbolFileCTF.h"
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Host/Config.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Symtab.h"
+#include "lldb/Symbol/TypeList.h"
+#include "lldb/Symbol/TypeMap.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/StreamBuffer.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/Timer.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+
+#include <memory>
+#include <optional>
+
+#if LLVM_ENABLE_ZLIB
+#include <zlib.h>
+#endif
+
+using namespace llvm;
+using namespace lldb;
+using namespace lldb_private;
+
+LLDB_PLUGIN_DEFINE(SymbolFileCTF)
+
+char SymbolFileCTF::ID;
+
+SymbolFileCTF::SymbolFileCTF(lldb::ObjectFileSP objfile_sp)
+ : SymbolFileCommon(std::move(objfile_sp)) {}
+
+void SymbolFileCTF::Initialize() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(), CreateInstance);
+}
+
+void SymbolFileCTF::Terminate() {
+ PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+llvm::StringRef SymbolFileCTF::GetPluginDescriptionStatic() {
+ return "Compact C Type Format Symbol Reader";
+}
+
+SymbolFile *SymbolFileCTF::CreateInstance(ObjectFileSP objfile_sp) {
+ return new SymbolFileCTF(std::move(objfile_sp));
+}
+
+bool SymbolFileCTF::ParseHeader() {
+ if (m_header)
+ return true;
+
+ Log *log = GetLog(LLDBLog::Symbols);
+
+ ModuleSP module_sp(m_objfile_sp->GetModule());
+ const SectionList *section_list = module_sp->GetSectionList();
+ if (!section_list)
+ return false;
+
+ SectionSP section_sp(
+ section_list->FindSectionByType(lldb::eSectionTypeCTF, true));
+ if (!section_sp)
+ return false;
+
+ m_objfile_sp->ReadSectionData(section_sp.get(), m_data);
+
+ if (m_data.GetByteSize() == 0)
+ return false;
+
+ StreamString module_desc;
+ GetObjectFile()->GetModule()->GetDescription(module_desc.AsRawOstream(),
+ lldb::eDescriptionLevelBrief);
+ LLDB_LOG(log, "Parsing Compact C Type format for {0}", module_desc.GetData());
+
+ lldb::offset_t offset = 0;
+
+ // Parse CTF header.
+ constexpr size_t ctf_header_size = sizeof(ctf_header_t);
+ if (!m_data.ValidOffsetForDataOfSize(offset, ctf_header_size)) {
+ LLDB_LOG(log, "CTF parsing failed: insufficient data for CTF header");
+ return false;
+ }
+
+ m_header.emplace();
+
+ ctf_header_t &ctf_header = *m_header;
+ ctf_header.preamble.magic = m_data.GetU16(&offset);
+ ctf_header.preamble.version = m_data.GetU8(&offset);
+ ctf_header.preamble.flags = m_data.GetU8(&offset);
+ ctf_header.parlabel = m_data.GetU32(&offset);
+ ctf_header.parname = m_data.GetU32(&offset);
+ ctf_header.lbloff = m_data.GetU32(&offset);
+ ctf_header.objtoff = m_data.GetU32(&offset);
+ ctf_header.funcoff = m_data.GetU32(&offset);
+ ctf_header.typeoff = m_data.GetU32(&offset);
+ ctf_header.stroff = m_data.GetU32(&offset);
+ ctf_header.strlen = m_data.GetU32(&offset);
+
+ // Validate the preamble.
+ if (ctf_header.preamble.magic != g_ctf_magic) {
+ LLDB_LOG(log, "CTF parsing failed: invalid magic: {0:x}",
+ ctf_header.preamble.magic);
+ return false;
+ }
+
+ if (ctf_header.preamble.version != g_ctf_version) {
+ LLDB_LOG(log, "CTF parsing failed: unsupported version: {0}",
+ ctf_header.preamble.version);
+ return false;
+ }
+
+ LLDB_LOG(log, "Parsed valid CTF preamble: version {0}, flags {1:x}",
+ ctf_header.preamble.version, ctf_header.preamble.flags);
+
+ m_body_offset = offset;
+
+ if (ctf_header.preamble.flags & eFlagCompress) {
+ // The body has been compressed with zlib deflate. Header offsets point into
+ // the decompressed data.
+#if LLVM_ENABLE_ZLIB
+ const std::size_t decompressed_size = ctf_header.stroff + ctf_header.strlen;
+ DataBufferSP decompressed_data =
+ std::make_shared<DataBufferHeap>(decompressed_size, 0x0);
+
+ z_stream zstr;
+ memset(&zstr, 0, sizeof(zstr));
+ zstr.next_in = (Bytef *)const_cast<uint8_t *>(m_data.GetDataStart() +
+ sizeof(ctf_header_t));
+ zstr.avail_in = m_data.BytesLeft(offset);
+ zstr.next_out =
+ (Bytef *)const_cast<uint8_t *>(decompressed_data->GetBytes());
+ zstr.avail_out = decompressed_size;
+
+ int rc = inflateInit(&zstr);
+ if (rc != Z_OK) {
+ LLDB_LOG(log, "CTF parsing failed: inflate initialization error: {0}",
+ zError(rc));
+ return false;
+ }
+
+ rc = inflate(&zstr, Z_FINISH);
+ if (rc != Z_STREAM_END) {
+ LLDB_LOG(log, "CTF parsing failed: inflate error: {0}", zError(rc));
+ return false;
+ }
+
+ rc = inflateEnd(&zstr);
+ if (rc != Z_OK) {
+ LLDB_LOG(log, "CTF parsing failed: inflate end error: {0}", zError(rc));
+ return false;
+ }
+
+ if (zstr.total_out != decompressed_size) {
+ LLDB_LOG(log,
+ "CTF parsing failed: decompressed size ({0}) doesn't match "
+ "expected size ([1})",
+ zstr.total_out, decompressed_size);
+ return false;
+ }
+
+ m_data = DataExtractor(decompressed_data, m_data.GetByteOrder(),
+ m_data.GetAddressByteSize());
+ m_body_offset = 0;
+#else
+ LLDB_LOG(
+ log,
+ "CTF parsing failed: data is compressed but no zlib inflate support");
+ return false;
+#endif
+ }
+
+ // Validate the header.
+ if (!m_data.ValidOffset(m_body_offset + ctf_header.lbloff)) {
+ LLDB_LOG(log,
+ "CTF parsing failed: invalid label section offset in header: {0}",
+ ctf_header.lbloff);
+ return false;
+ }
+
+ if (!m_data.ValidOffset(m_body_offset + ctf_header.objtoff)) {
+ LLDB_LOG(log,
+ "CTF parsing failed: invalid object section offset in header: {0}",
+ ctf_header.objtoff);
+ return false;
+ }
+
+ if (!m_data.ValidOffset(m_body_offset + ctf_header.funcoff)) {
+ LLDB_LOG(
+ log,
+ "CTF parsing failed: invalid function section offset in header: {0}",
+ ctf_header.funcoff);
+ return false;
+ }
+
+ if (!m_data.ValidOffset(m_body_offset + ctf_header.typeoff)) {
+ LLDB_LOG(log,
+ "CTF parsing failed: invalid type section offset in header: {0}",
+ ctf_header.typeoff);
+ return false;
+ }
+
+ if (!m_data.ValidOffset(m_body_offset + ctf_header.stroff)) {
+ LLDB_LOG(log,
+ "CTF parsing failed: invalid string section offset in header: {0}",
+ ctf_header.stroff);
+ return false;
+ }
+
+ const lldb::offset_t str_end_offset =
+ m_body_offset + ctf_header.stroff + ctf_header.strlen;
+ if (!m_data.ValidOffset(str_end_offset - 1)) {
+ LLDB_LOG(log,
+ "CTF parsing failed: invalid string section length in header: {0}",
+ ctf_header.strlen);
+ return false;
+ }
+
+ if (m_body_offset + ctf_header.stroff + ctf_header.parlabel >
+ str_end_offset) {
+ LLDB_LOG(log,
+ "CTF parsing failed: invalid parent label offset: {0} exceeds end "
+ "of string section ({1})",
+ ctf_header.parlabel, str_end_offset);
+ return false;
+ }
+
+ if (m_body_offset + ctf_header.stroff + ctf_header.parname > str_end_offset) {
+ LLDB_LOG(log,
+ "CTF parsing failed: invalid parent name offset: {0} exceeds end "
+ "of string section ({1})",
+ ctf_header.parname, str_end_offset);
+ return false;
+ }
+
+ LLDB_LOG(log,
+ "Parsed valid CTF header: lbloff = {0}, objtoff = {1}, funcoff = "
+ "{2}, typeoff = {3}, stroff = {4}, strlen = {5}",
+ ctf_header.lbloff, ctf_header.objtoff, ctf_header.funcoff,
+ ctf_header.typeoff, ctf_header.stroff, ctf_header.strlen);
+
+ return true;
+}
+
+void SymbolFileCTF::InitializeObject() {
+ Log *log = GetLog(LLDBLog::Symbols);
+
+ auto type_system_or_err = GetTypeSystemForLanguage(lldb::eLanguageTypeC);
+ if (auto err = type_system_or_err.takeError()) {
+ LLDB_LOG_ERROR(log, std::move(err), "Unable to get type system: {0}");
+ return;
+ }
+
+ auto ts = *type_system_or_err;
+ m_ast = llvm::dyn_cast_or_null<TypeSystemClang>(ts.get());
+ LazyBool optimized = eLazyBoolNo;
+ m_comp_unit_sp = std::make_shared<CompileUnit>(
+ m_objfile_sp->GetModule(), nullptr, "", 0, eLanguageTypeC, optimized);
+
+ ParseTypes(*m_comp_unit_sp);
+}
+
+llvm::StringRef SymbolFileCTF::ReadString(lldb::offset_t str_offset) const {
+ lldb::offset_t offset = m_body_offset + m_header->stroff + str_offset;
+ if (!m_data.ValidOffset(offset))
+ return "(invalid)";
+ const char *str = m_data.GetCStr(&offset);
+ if (str && !*str)
+ return "(anon)";
+ return llvm::StringRef(str);
+}
+
+/// Return the integer display representation encoded in the given data.
+static uint32_t GetEncoding(uint32_t data) {
+ // Mask bits 24–31.
+ return ((data)&0xff000000) >> 24;
+}
+
+/// Return the integral width in bits encoded in the given data.
+static uint32_t GetBits(uint32_t data) {
+ // Mask bits 0-15.
+ return (data)&0x0000ffff;
+}
+
+/// Return the type kind encoded in the given data.
+uint32_t GetKind(uint32_t data) {
+ // Mask bits 26–31.
+ return ((data)&0xf800) >> 11;
+}
+
+/// Return the variable length encoded in the given data.
+uint32_t GetVLen(uint32_t data) {
+ // Mask bits 0–24.
+ return (data)&0x3ff;
+}
+
+static uint32_t GetBytes(uint32_t bits) { return bits / sizeof(unsigned); }
+
+static clang::TagTypeKind TranslateRecordKind(CTFType::Kind type) {
+ switch (type) {
+ case CTFType::Kind::eStruct:
+ return clang::TagTypeKind::Struct;
+ case CTFType::Kind::eUnion:
+ return clang::TagTypeKind::Union;
+ default:
+ lldbassert(false && "Invalid record kind!");
+ return clang::TagTypeKind::Struct;
+ }
+}
+
+llvm::Expected<TypeSP>
+SymbolFileCTF::CreateInteger(const CTFInteger &ctf_integer) {
+ lldb::BasicType basic_type =
+ TypeSystemClang::GetBasicTypeEnumeration(ctf_integer.name);
+ if (basic_type == eBasicTypeInvalid)
+ return llvm::make_error<llvm::StringError>(
+ llvm::formatv("unsupported integer type: no corresponding basic clang "
+ "type for '{0}'",
+ ctf_integer.name),
+ llvm::inconvertibleErrorCode());
+
+ CompilerType compiler_type = m_ast->GetBasicType(basic_type);
+
+ if (basic_type != eBasicTypeVoid && basic_type != eBasicTypeBool) {
+ // Make sure the type we got is an integer type.
+ bool compiler_type_is_signed = false;
+ if (!compiler_type.IsIntegerType(compiler_type_is_signed))
+ return llvm::make_error<llvm::StringError>(
+ llvm::formatv(
+ "Found compiler type for '{0}' but it's not an integer type: {1}",
+ ctf_integer.name,
+ compiler_type.GetDisplayTypeName().GetStringRef()),
+ llvm::inconvertibleErrorCode());
+
+ // Make sure the signing matches between the CTF and the compiler type.
+ const bool type_is_signed = (ctf_integer.encoding & IntEncoding::eSigned);
+ if (compiler_type_is_signed != type_is_signed)
+ return llvm::make_error<llvm::StringError>(
+ llvm::formatv("Found integer compiler type for {0} but compiler type "
+ "is {1} and {0} is {2}",
+ ctf_integer.name,
+ compiler_type_is_signed ? "signed" : "unsigned",
+ type_is_signed ? "signed" : "unsigned"),
+ llvm::inconvertibleErrorCode());
+ }
+
+ Declaration decl;
+ return MakeType(ctf_integer.uid, ConstString(ctf_integer.name),
+ GetBytes(ctf_integer.bits), nullptr, LLDB_INVALID_UID,
+ lldb_private::Type::eEncodingIsUID, decl, compiler_type,
+ lldb_private::Type::ResolveState::Full);
+}
+
+llvm::Expected<lldb::TypeSP>
+SymbolFileCTF::CreateModifier(const CTFModifier &ctf_modifier) {
+ Type *ref_type = ResolveTypeUID(ctf_modifier.type);
+ if (!ref_type)
+ return llvm::make_error<llvm::StringError>(
+ llvm::formatv("Could not find modified type: {0}", ctf_modifier.type),
+ llvm::inconvertibleErrorCode());
+
+ CompilerType compiler_type;
+
+ switch (ctf_modifier.kind) {
+ case CTFType::ePointer:
+ compiler_type = ref_type->GetFullCompilerType().GetPointerType();
+ break;
+ case CTFType::eConst:
+ compiler_type = ref_type->GetFullCompilerType().AddConstModifier();
+ break;
+ case CTFType::eVolatile:
+ compiler_type = ref_type->GetFullCompilerType().AddVolatileModifier();
+ break;
+ case CTFType::eRestrict:
+ compiler_type = ref_type->GetFullCompilerType().AddRestrictModifier();
+ break;
+ default:
+ return llvm::make_error<llvm::StringError>(
+ llvm::formatv("ParseModifier called with unsupported kind: {0}",
+ ctf_modifier.kind),
+ llvm::inconvertibleErrorCode());
+ }
+
+ Declaration decl;
+ return MakeType(ctf_modifier.uid, ConstString(), 0, nullptr, LLDB_INVALID_UID,
+ Type::eEncodingIsUID, decl, compiler_type,
+ lldb_private::Type::ResolveState::Full);
+}
+
+llvm::Expected<lldb::TypeSP>
+SymbolFileCTF::CreateTypedef(const CTFTypedef &ctf_typedef) {
+ Type *underlying_type = ResolveTypeUID(ctf_typedef.type);
+ if (!underlying_type)
+ return llvm::make_error<llvm::StringError>(
+ llvm::formatv("Could not find typedef underlying type: {0}",
+ ctf_typedef.type),
+ llvm::inconvertibleErrorCode());
+
+ CompilerType target_ast_type = underlying_type->GetFullCompilerType();
+ clang::DeclContext *decl_ctx = m_ast->GetTranslationUnitDecl();
+ CompilerType ast_typedef = target_ast_type.CreateTypedef(
+ ctf_typedef.name.data(), m_ast->CreateDeclContext(decl_ctx), 0);
+
+ Declaration decl;
+ return MakeType(ctf_typedef.uid, ConstString(ctf_typedef.name), 0, nullptr,
+ LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl,
+ ast_typedef, lldb_private::Type::ResolveState::Full);
+}
+
+llvm::Expected<lldb::TypeSP>
+SymbolFileCTF::CreateArray(const CTFArray &ctf_array) {
+ Type *element_type = ResolveTypeUID(ctf_array.type);
+ if (!element_type)
+ return llvm::make_error<llvm::StringError>(
+ llvm::formatv("Could not find array element type: {0}", ctf_array.type),
+ llvm::inconvertibleErrorCode());
+
+ std::optional<uint64_t> element_size = element_type->GetByteSize(nullptr);
+ if (!element_size)
+ return llvm::make_error<llvm::StringError>(
+ llvm::formatv("could not get element size of type: {0}",
+ ctf_array.type),
+ llvm::inconvertibleErrorCode());
+
+ uint64_t size = ctf_array.nelems * *element_size;
+
+ CompilerType compiler_type = m_ast->CreateArrayType(
+ element_type->GetFullCompilerType(), ctf_array.nelems,
+ /*is_gnu_vector*/ false);
+
+ Declaration decl;
+ return MakeType(ctf_array.uid, ConstString(), size, nullptr, LLDB_INVALID_UID,
+ Type::eEncodingIsUID, decl, compiler_type,
+ lldb_private::Type::ResolveState::Full);
+}
+
+llvm::Expected<lldb::TypeSP>
+SymbolFileCTF::CreateEnum(const CTFEnum &ctf_enum) {
+ Declaration decl;
+ CompilerType enum_type = m_ast->CreateEnumerationType(
+ ctf_enum.name, m_ast->GetTranslationUnitDecl(), OptionalClangModuleID(),
+ decl, m_ast->GetBasicType(eBasicTypeInt),
+ /*is_scoped=*/false);
+
+ for (const CTFEnum::Value &value : ctf_enum.values) {
+ Declaration value_decl;
+ m_ast->AddEnumerationValueToEnumerationType(
+ enum_type, value_decl, value.name.data(), value.value, ctf_enum.size);
+ }
+ TypeSystemClang::CompleteTagDeclarationDefinition(enum_type);
+
+ return MakeType(ctf_enum.uid, ConstString(), 0, nullptr, LLDB_INVALID_UID,
+ Type::eEncodingIsUID, decl, enum_type,
+ lldb_private::Type::ResolveState::Full);
+}
+
+llvm::Expected<lldb::TypeSP>
+SymbolFileCTF::CreateFunction(const CTFFunction &ctf_function) {
+ std::vector<CompilerType> arg_types;
+ for (uint32_t arg : ctf_function.args) {
+ if (Type *arg_type = ResolveTypeUID(arg))
+ arg_types.push_back(arg_type->GetFullCompilerType());
+ }
+
+ Type *ret_type = ResolveTypeUID(ctf_function.return_type);
+ if (!ret_type)
+ return llvm::make_error<llvm::StringError>(
+ llvm::formatv("Could not find function return type: {0}",
+ ctf_function.return_type),
+ llvm::inconvertibleErrorCode());
+
+ CompilerType func_type = m_ast->CreateFunctionType(
+ ret_type->GetFullCompilerType(), arg_types.data(), arg_types.size(),
+ ctf_function.variadic, 0, clang::CallingConv::CC_C);
+
+ Declaration decl;
+ return MakeType(ctf_function.uid, ConstString(ctf_function.name), 0, nullptr,
+ LLDB_INVALID_UID, Type::eEncodingIsUID, decl, func_type,
+ lldb_private::Type::ResolveState::Full);
+}
+
+llvm::Expected<lldb::TypeSP>
+SymbolFileCTF::CreateRecord(const CTFRecord &ctf_record) {
+ const clang::TagTypeKind tag_kind = TranslateRecordKind(ctf_record.kind);
+ CompilerType record_type = m_ast->CreateRecordType(
+ nullptr, OptionalClangModuleID(), eAccessPublic, ctf_record.name.data(),
+ llvm::to_underlying(tag_kind), eLanguageTypeC);
+ m_compiler_types[record_type.GetOpaqueQualType()] = &ctf_record;
+ Declaration decl;
+ return MakeType(ctf_record.uid, ConstString(ctf_record.name), ctf_record.size,
+ nullptr, LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID,
+ decl, record_type, lldb_private::Type::ResolveState::Forward);
+}
+
+bool SymbolFileCTF::CompleteType(CompilerType &compiler_type) {
+ // Check if we have a CTF type for the given incomplete compiler type.
+ auto it = m_compiler_types.find(compiler_type.GetOpaqueQualType());
+ if (it == m_compiler_types.end())
+ return false;
+
+ const CTFType *ctf_type = it->second;
+ assert(ctf_type && "m_compiler_types should only contain valid CTF types");
+
+ // We only support resolving record types.
+ assert(llvm::isa<CTFRecord>(ctf_type));
+
+ // Cast to the appropriate CTF type.
+ const CTFRecord *ctf_record = static_cast<const CTFRecord *>(ctf_type);
+
+ // If any of the fields are incomplete, we cannot complete the type.
+ for (const CTFRecord::Field &field : ctf_record->fields) {
+ if (!ResolveTypeUID(field.type)) {
+ LLDB_LOG(GetLog(LLDBLog::Symbols),
+ "Cannot complete type {0} because field {1} is incomplete",
+ ctf_type->uid, field.type);
+ return false;
+ }
+ }
+
+ // Complete the record type.
+ m_ast->StartTagDeclarationDefinition(compiler_type);
+ for (const CTFRecord::Field &field : ctf_record->fields) {
+ Type *field_type = ResolveTypeUID(field.type);
+ assert(field_type && "field must be complete");
+ const uint32_t field_size = field_type->GetByteSize(nullptr).value_or(0);
+ TypeSystemClang::AddFieldToRecordType(compiler_type, field.name,
+ field_type->GetFullCompilerType(),
+ eAccessPublic, field_size);
+ }
+ m_ast->CompleteTagDeclarationDefinition(compiler_type);
+
+ // Now that the compiler type is complete, we don't need to remember it
+ // anymore and can remove the CTF record type.
+ m_compiler_types.erase(compiler_type.GetOpaqueQualType());
+ m_ctf_types.erase(ctf_type->uid);
+
+ return true;
+}
+
+llvm::Expected<lldb::TypeSP>
+SymbolFileCTF::CreateForward(const CTFForward &ctf_forward) {
+ CompilerType forward_compiler_type = m_ast->CreateRecordType(
+ nullptr, OptionalClangModuleID(), eAccessPublic, ctf_forward.name,
+ llvm::to_underlying(clang::TagTypeKind::Struct), eLanguageTypeC);
+ Declaration decl;
+ return MakeType(ctf_forward.uid, ConstString(ctf_forward.name), 0, nullptr,
+ LLDB_INVALID_UID, Type::eEncodingIsUID, decl,
+ forward_compiler_type, Type::ResolveState::Forward);
+}
+
+llvm::Expected<TypeSP> SymbolFileCTF::CreateType(CTFType *ctf_type) {
+ if (!ctf_type)
+ return llvm::make_error<llvm::StringError>(
+ "cannot create type for unparsed type", llvm::inconvertibleErrorCode());
+
+ switch (ctf_type->kind) {
+ case CTFType::Kind::eInteger:
+ return CreateInteger(*static_cast<CTFInteger *>(ctf_type));
+ case CTFType::Kind::eConst:
+ case CTFType::Kind::ePointer:
+ case CTFType::Kind::eRestrict:
+ case CTFType::Kind::eVolatile:
+ return CreateModifier(*static_cast<CTFModifier *>(ctf_type));
+ case CTFType::Kind::eTypedef:
+ return CreateTypedef(*static_cast<CTFTypedef *>(ctf_type));
+ case CTFType::Kind::eArray:
+ return CreateArray(*static_cast<CTFArray *>(ctf_type));
+ case CTFType::Kind::eEnum:
+ return CreateEnum(*static_cast<CTFEnum *>(ctf_type));
+ case CTFType::Kind::eFunction:
+ return CreateFunction(*static_cast<CTFFunction *>(ctf_type));
+ case CTFType::Kind::eStruct:
+ case CTFType::Kind::eUnion:
+ return CreateRecord(*static_cast<CTFRecord *>(ctf_type));
+ case CTFType::Kind::eForward:
+ return CreateForward(*static_cast<CTFForward *>(ctf_type));
+ case CTFType::Kind::eUnknown:
+ case CTFType::Kind::eFloat:
+ case CTFType::Kind::eSlice:
+ return llvm::make_error<llvm::StringError>(
+ llvm::formatv("unsupported type (uid = {0}, name = {1}, kind = {2})",
+ ctf_type->uid, ctf_type->name, ctf_type->kind),
+ llvm::inconvertibleErrorCode());
+ }
+ llvm_unreachable("Unexpected CTF type kind");
+}
+
+llvm::Expected<std::unique_ptr<CTFType>>
+SymbolFileCTF::ParseType(lldb::offset_t &offset, lldb::user_id_t uid) {
+ ctf_stype_t ctf_stype;
+ ctf_stype.name = m_data.GetU32(&offset);
+ ctf_stype.info = m_data.GetU32(&offset);
+ ctf_stype.size = m_data.GetU32(&offset);
+
+ llvm::StringRef name = ReadString(ctf_stype.name);
+ const uint32_t kind = GetKind(ctf_stype.info);
+ const uint32_t variable_length = GetVLen(ctf_stype.info);
+ const uint32_t type = ctf_stype.GetType();
+ const uint32_t size = ctf_stype.GetSize();
+
+ switch (kind) {
+ case TypeKind::eInteger: {
+ const uint32_t vdata = m_data.GetU32(&offset);
+ const uint32_t bits = GetBits(vdata);
+ const uint32_t encoding = GetEncoding(vdata);
+ return std::make_unique<CTFInteger>(uid, name, bits, encoding);
+ }
+ case TypeKind::eConst:
+ return std::make_unique<CTFConst>(uid, type);
+ case TypeKind::ePointer:
+ return std::make_unique<CTFPointer>(uid, type);
+ case TypeKind::eRestrict:
+ return std::make_unique<CTFRestrict>(uid, type);
+ case TypeKind::eVolatile:
+ return std::make_unique<CTFVolatile>(uid, type);
+ case TypeKind::eTypedef:
+ return std::make_unique<CTFTypedef>(uid, name, type);
+ case TypeKind::eArray: {
+ const uint32_t type = m_data.GetU32(&offset);
+ const uint32_t index = m_data.GetU32(&offset);
+ const uint32_t nelems = m_data.GetU32(&offset);
+ return std::make_unique<CTFArray>(uid, name, type, index, nelems);
+ }
+ case TypeKind::eEnum: {
+ std::vector<CTFEnum::Value> values;
+ for (uint32_t i = 0; i < variable_length; ++i) {
+ const uint32_t value_name = m_data.GetU32(&offset);
+ const uint32_t value = m_data.GetU32(&offset);
+ values.emplace_back(ReadString(value_name), value);
+ }
+ return std::make_unique<CTFEnum>(uid, name, variable_length, size, values);
+ }
+ case TypeKind::eFunction: {
+ std::vector<uint32_t> args;
+ bool variadic = false;
+ for (uint32_t i = 0; i < variable_length; ++i) {
+ const uint32_t arg_uid = m_data.GetU32(&offset);
+ // If the last argument is 0, this is a variadic function.
+ if (arg_uid == 0) {
+ variadic = true;
+ break;
+ }
+ args.push_back(arg_uid);
+ }
+ // If the number of arguments is odd, a single uint32_t of padding is
+ // inserted to maintain alignment.
+ if (variable_length % 2 == 1)
+ m_data.GetU32(&offset);
+ return std::make_unique<CTFFunction>(uid, name, variable_length, type, args,
+ variadic);
+ }
+ case TypeKind::eStruct:
+ case TypeKind::eUnion: {
+ std::vector<CTFRecord::Field> fields;
+ for (uint32_t i = 0; i < variable_length; ++i) {
+ const uint32_t field_name = m_data.GetU32(&offset);
+ const uint32_t type = m_data.GetU32(&offset);
+ uint64_t field_offset = 0;
+ if (size < g_ctf_field_threshold) {
+ field_offset = m_data.GetU16(&offset);
+ m_data.GetU16(&offset); // Padding
+ } else {
+ const uint32_t offset_hi = m_data.GetU32(&offset);
+ const uint32_t offset_lo = m_data.GetU32(&offset);
+ field_offset = (((uint64_t)offset_hi) << 32) | ((uint64_t)offset_lo);
+ }
+ fields.emplace_back(ReadString(field_name), type, field_offset);
+ }
+ return std::make_unique<CTFRecord>(static_cast<CTFType::Kind>(kind), uid,
+ name, variable_length, size, fields);
+ }
+ case TypeKind::eForward:
+ return std::make_unique<CTFForward>(uid, name);
+ case TypeKind::eUnknown:
+ return std::make_unique<CTFType>(static_cast<CTFType::Kind>(kind), uid,
+ name);
+ case TypeKind::eFloat:
+ case TypeKind::eSlice:
+ offset += (variable_length * sizeof(uint32_t));
+ break;
+ }
+
+ return llvm::make_error<llvm::StringError>(
+ llvm::formatv("unsupported type (name = {0}, kind = {1}, vlength = {2})",
+ name, kind, variable_length),
+ llvm::inconvertibleErrorCode());
+}
+
+size_t SymbolFileCTF::ParseTypes(CompileUnit &cu) {
+ if (!ParseHeader())
+ return 0;
+
+ if (!m_types.empty())
+ return 0;
+
+ if (!m_ast)
+ return 0;
+
+ Log *log = GetLog(LLDBLog::Symbols);
+ LLDB_LOG(log, "Parsing CTF types");
+
+ lldb::offset_t type_offset = m_body_offset + m_header->typeoff;
+ const lldb::offset_t type_offset_end = m_body_offset + m_header->stroff;
+
+ lldb::user_id_t type_uid = 1;
+ while (type_offset < type_offset_end) {
+ llvm::Expected<std::unique_ptr<CTFType>> type_or_error =
+ ParseType(type_offset, type_uid);
+ if (type_or_error) {
+ m_ctf_types[(*type_or_error)->uid] = std::move(*type_or_error);
+ } else {
+ LLDB_LOG_ERROR(log, type_or_error.takeError(),
+ "Failed to parse type {1} at offset {2}: {0}", type_uid,
+ type_offset);
+ }
+ type_uid++;
+ }
+
+ LLDB_LOG(log, "Parsed {0} CTF types", m_ctf_types.size());
+
+ for (lldb::user_id_t uid = 1; uid < type_uid; ++uid)
+ ResolveTypeUID(uid);
+
+ LLDB_LOG(log, "Created {0} CTF types", m_types.size());
+
+ return m_types.size();
+}
+
+size_t SymbolFileCTF::ParseFunctions(CompileUnit &cu) {
+ if (!ParseHeader())
+ return 0;
+
+ if (!m_functions.empty())
+ return 0;
+
+ if (!m_ast)
+ return 0;
+
+ Symtab *symtab = GetObjectFile()->GetModule()->GetSymtab();
+ if (!symtab)
+ return 0;
+
+ Log *log = GetLog(LLDBLog::Symbols);
+ LLDB_LOG(log, "Parsing CTF functions");
+
+ lldb::offset_t function_offset = m_body_offset + m_header->funcoff;
+ const lldb::offset_t function_offset_end = m_body_offset + m_header->typeoff;
+
+ uint32_t symbol_idx = 0;
+ Declaration decl;
+ while (function_offset < function_offset_end) {
+ const uint32_t info = m_data.GetU32(&function_offset);
+ const uint16_t kind = GetKind(info);
+ const uint16_t variable_length = GetVLen(info);
+
+ Symbol *symbol = symtab->FindSymbolWithType(
+ eSymbolTypeCode, Symtab::eDebugYes, Symtab::eVisibilityAny, symbol_idx);
+
+ // Skip padding.
+ if (kind == TypeKind::eUnknown && variable_length == 0)
+ continue;
+
+ // Skip unexpected kinds.
+ if (kind != TypeKind::eFunction)
+ continue;
+
+ const uint32_t ret_uid = m_data.GetU32(&function_offset);
+ const uint32_t num_args = variable_length;
+
+ std::vector<CompilerType> arg_types;
+ arg_types.reserve(num_args);
+
+ bool is_variadic = false;
+ for (uint32_t i = 0; i < variable_length; i++) {
+ const uint32_t arg_uid = m_data.GetU32(&function_offset);
+
+ // If the last argument is 0, this is a variadic function.
+ if (arg_uid == 0) {
+ is_variadic = true;
+ break;
+ }
+
+ Type *arg_type = ResolveTypeUID(arg_uid);
+ arg_types.push_back(arg_type ? arg_type->GetFullCompilerType()
+ : CompilerType());
+ }
+
+ if (symbol) {
+ Type *ret_type = ResolveTypeUID(ret_uid);
+ AddressRange func_range =
+ AddressRange(symbol->GetFileAddress(), symbol->GetByteSize(),
+ GetObjectFile()->GetModule()->GetSectionList());
+
+ // Create function type.
+ CompilerType func_type = m_ast->CreateFunctionType(
+ ret_type ? ret_type->GetFullCompilerType() : CompilerType(),
+ arg_types.data(), arg_types.size(), is_variadic, 0,
+ clang::CallingConv::CC_C);
+ lldb::user_id_t function_type_uid = m_types.size() + 1;
+ TypeSP type_sp =
+ MakeType(function_type_uid, symbol->GetName(), 0, nullptr,
+ LLDB_INVALID_UID, Type::eEncodingIsUID, decl, func_type,
+ lldb_private::Type::ResolveState::Full);
+ m_types[function_type_uid] = type_sp;
+
+ // Create function.
+ lldb::user_id_t func_uid = m_functions.size();
+ FunctionSP function_sp = std::make_shared<Function>(
+ &cu, func_uid, function_type_uid, symbol->GetMangled(), type_sp.get(),
+ func_range);
+ m_functions.emplace_back(function_sp);
+ cu.AddFunction(function_sp);
+ }
+ }
+
+ LLDB_LOG(log, "CTF parsed {0} functions", m_functions.size());
+
+ return m_functions.size();
+}
+
+static DWARFExpression CreateDWARFExpression(ModuleSP module_sp,
+ const Symbol &symbol) {
+ if (!module_sp)
+ return DWARFExpression();
+
+ const ArchSpec &architecture = module_sp->GetArchitecture();
+ ByteOrder byte_order = architecture.GetByteOrder();
+ uint32_t address_size = architecture.GetAddressByteSize();
+ uint32_t byte_size = architecture.GetDataByteSize();
+
+ StreamBuffer<32> stream(Stream::eBinary, address_size, byte_order);
+ stream.PutHex8(lldb_private::dwarf::DW_OP_addr);
+ stream.PutMaxHex64(symbol.GetFileAddress(), address_size, byte_order);
+
+ DataBufferSP buffer =
+ std::make_shared<DataBufferHeap>(stream.GetData(), stream.GetSize());
+ lldb_private::DataExtractor extractor(buffer, byte_order, address_size,
+ byte_size);
+ DWARFExpression result(extractor);
+ result.SetRegisterKind(eRegisterKindDWARF);
+
+ return result;
+}
+
+size_t SymbolFileCTF::ParseObjects(CompileUnit &comp_unit) {
+ if (!ParseHeader())
+ return 0;
+
+ if (!m_variables.empty())
+ return 0;
+
+ if (!m_ast)
+ return 0;
+
+ ModuleSP module_sp = GetObjectFile()->GetModule();
+ Symtab *symtab = module_sp->GetSymtab();
+ if (!symtab)
+ return 0;
+
+ Log *log = GetLog(LLDBLog::Symbols);
+ LLDB_LOG(log, "Parsing CTF objects");
+
+ lldb::offset_t object_offset = m_body_offset + m_header->objtoff;
+ const lldb::offset_t object_offset_end = m_body_offset + m_header->funcoff;
+
+ uint32_t symbol_idx = 0;
+ Declaration decl;
+ while (object_offset < object_offset_end) {
+ const uint32_t type_uid = m_data.GetU32(&object_offset);
+
+ if (Symbol *symbol =
+ symtab->FindSymbolWithType(eSymbolTypeData, Symtab::eDebugYes,
+ Symtab::eVisibilityAny, symbol_idx)) {
+ Variable::RangeList ranges;
+ ranges.Append(symbol->GetFileAddress(), symbol->GetByteSize());
+
+ auto type_sp = std::make_shared<SymbolFileType>(*this, type_uid);
+
+ DWARFExpressionList location(
+ module_sp, CreateDWARFExpression(module_sp, *symbol), nullptr);
+
+ lldb::user_id_t variable_type_uid = m_variables.size();
+ m_variables.emplace_back(std::make_shared<Variable>(
+ variable_type_uid, symbol->GetName().AsCString(),
+ symbol->GetName().AsCString(), type_sp, eValueTypeVariableGlobal,
+ m_comp_unit_sp.get(), ranges, &decl, location, symbol->IsExternal(),
+ /*artificial=*/false,
+ /*location_is_constant_data*/ false));
+ }
+ }
+
+ LLDB_LOG(log, "Parsed {0} CTF objects", m_variables.size());
+
+ return m_variables.size();
+}
+
+uint32_t SymbolFileCTF::CalculateAbilities() {
+ if (!m_objfile_sp)
+ return 0;
+
+ if (!ParseHeader())
+ return 0;
+
+ return VariableTypes | Functions | GlobalVariables;
+}
+
+uint32_t SymbolFileCTF::ResolveSymbolContext(const Address &so_addr,
+ SymbolContextItem resolve_scope,
+ SymbolContext &sc) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ if (m_objfile_sp->GetSymtab() == nullptr)
+ return 0;
+
+ uint32_t resolved_flags = 0;
+
+ // Resolve symbols.
+ if (resolve_scope & eSymbolContextSymbol) {
+ sc.symbol = m_objfile_sp->GetSymtab()->FindSymbolContainingFileAddress(
+ so_addr.GetFileAddress());
+ if (sc.symbol)
+ resolved_flags |= eSymbolContextSymbol;
+ }
+
+ // Resolve functions.
+ if (resolve_scope & eSymbolContextFunction) {
+ for (FunctionSP function_sp : m_functions) {
+ if (function_sp->GetAddressRange().ContainsFileAddress(
+ so_addr.GetFileAddress())) {
+ sc.function = function_sp.get();
+ resolved_flags |= eSymbolContextFunction;
+ break;
+ }
+ }
+ }
+
+ // Resolve variables.
+ if (resolve_scope & eSymbolContextVariable) {
+ for (VariableSP variable_sp : m_variables) {
+ if (variable_sp->LocationIsValidForAddress(so_addr.GetFileAddress())) {
+ sc.variable = variable_sp.get();
+ break;
+ }
+ }
+ }
+
+ return resolved_flags;
+}
+
+CompUnitSP SymbolFileCTF::ParseCompileUnitAtIndex(uint32_t idx) {
+ if (idx == 0)
+ return m_comp_unit_sp;
+ return {};
+}
+
+size_t
+SymbolFileCTF::ParseVariablesForContext(const lldb_private::SymbolContext &sc) {
+ return ParseObjects(*m_comp_unit_sp);
+}
+
+void SymbolFileCTF::AddSymbols(Symtab &symtab) {
+ // CTF does not encode symbols.
+ // We rely on the existing symbol table to map symbols to type.
+}
+
+lldb_private::Type *SymbolFileCTF::ResolveTypeUID(lldb::user_id_t type_uid) {
+ auto type_it = m_types.find(type_uid);
+ if (type_it != m_types.end())
+ return type_it->second.get();
+
+ auto ctf_type_it = m_ctf_types.find(type_uid);
+ if (ctf_type_it == m_ctf_types.end())
+ return nullptr;
+
+ CTFType *ctf_type = ctf_type_it->second.get();
+ assert(ctf_type && "m_ctf_types should only contain valid CTF types");
+
+ Log *log = GetLog(LLDBLog::Symbols);
+
+ llvm::Expected<TypeSP> type_or_error = CreateType(ctf_type);
+ if (!type_or_error) {
+ LLDB_LOG_ERROR(log, type_or_error.takeError(),
+ "Failed to create type for {1}: {0}", ctf_type->uid);
+ return {};
+ }
+
+ TypeSP type_sp = *type_or_error;
+
+ if (log) {
+ StreamString ss;
+ type_sp->Dump(&ss, true);
+ LLDB_LOGV(log, "Adding type {0}: {1}", type_sp->GetID(),
+ llvm::StringRef(ss.GetString()).rtrim());
+ }
+
+ m_types[type_uid] = type_sp;
+
+ // Except for record types which we'll need to complete later, we don't need
+ // the CTF type anymore.
+ if (!isa<CTFRecord>(ctf_type))
+ m_ctf_types.erase(type_uid);
+
+ return type_sp.get();
+}
+
+void SymbolFileCTF::FindTypes(const lldb_private::TypeQuery &match,
+ lldb_private::TypeResults &results) {
+ // Make sure we haven't already searched this SymbolFile before.
+ if (results.AlreadySearched(this))
+ return;
+
+ ConstString name = match.GetTypeBasename();
+ for (TypeSP type_sp : GetTypeList().Types()) {
+ if (type_sp && type_sp->GetName() == name) {
+ results.InsertUnique(type_sp);
+ if (results.Done(match))
+ return;
+ }
+ }
+}
+
+void SymbolFileCTF::FindTypesByRegex(
+ const lldb_private::RegularExpression &regex, uint32_t max_matches,
+ lldb_private::TypeMap &types) {
+ ParseTypes(*m_comp_unit_sp);
+
+ size_t matches = 0;
+ for (TypeSP type_sp : GetTypeList().Types()) {
+ if (matches == max_matches)
+ break;
+ if (type_sp && regex.Execute(type_sp->GetName()))
+ types.Insert(type_sp);
+ matches++;
+ }
+}
+
+void SymbolFileCTF::FindFunctions(
+ const lldb_private::Module::LookupInfo &lookup_info,
+ const lldb_private::CompilerDeclContext &parent_decl_ctx,
+ bool include_inlines, lldb_private::SymbolContextList &sc_list) {
+ ParseFunctions(*m_comp_unit_sp);
+
+ ConstString name = lookup_info.GetLookupName();
+ for (FunctionSP function_sp : m_functions) {
+ if (function_sp && function_sp->GetName() == name) {
+ lldb_private::SymbolContext sc;
+ sc.comp_unit = m_comp_unit_sp.get();
+ sc.function = function_sp.get();
+ sc_list.Append(sc);
+ }
+ }
+}
+
+void SymbolFileCTF::FindFunctions(const lldb_private::RegularExpression &regex,
+ bool include_inlines,
+ lldb_private::SymbolContextList &sc_list) {
+ for (FunctionSP function_sp : m_functions) {
+ if (function_sp && regex.Execute(function_sp->GetName())) {
+ lldb_private::SymbolContext sc;
+ sc.comp_unit = m_comp_unit_sp.get();
+ sc.function = function_sp.get();
+ sc_list.Append(sc);
+ }
+ }
+}
+
+void SymbolFileCTF::FindGlobalVariables(
+ lldb_private::ConstString name,
+ const lldb_private::CompilerDeclContext &parent_decl_ctx,
+ uint32_t max_matches, lldb_private::VariableList &variables) {
+ ParseObjects(*m_comp_unit_sp);
+
+ size_t matches = 0;
+ for (VariableSP variable_sp : m_variables) {
+ if (matches == max_matches)
+ break;
+ if (variable_sp && variable_sp->GetName() == name) {
+ variables.AddVariable(variable_sp);
+ matches++;
+ }
+ }
+}
+
+void SymbolFileCTF::FindGlobalVariables(
+ const lldb_private::RegularExpression &regex, uint32_t max_matches,
+ lldb_private::VariableList &variables) {
+ ParseObjects(*m_comp_unit_sp);
+
+ size_t matches = 0;
+ for (VariableSP variable_sp : m_variables) {
+ if (matches == max_matches)
+ break;
+ if (variable_sp && regex.Execute(variable_sp->GetName())) {
+ variables.AddVariable(variable_sp);
+ matches++;
+ }
+ }
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.h
new file mode 100644
index 000000000000..3a80138fffbc
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.h
@@ -0,0 +1,264 @@
+//===-- SymbolFileCTF.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_CTF_SYMBOLFILECTF_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_CTF_SYMBOLFILECTF_H
+
+#include <map>
+#include <optional>
+#include <vector>
+
+#include "CTFTypes.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/SymbolFile.h"
+
+namespace lldb_private {
+
+class SymbolFileCTF : public lldb_private::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); }
+ /// \}
+
+ SymbolFileCTF(lldb::ObjectFileSP objfile_sp);
+
+ static void Initialize();
+
+ static void Terminate();
+
+ static llvm::StringRef GetPluginNameStatic() { return "CTF"; }
+
+ static llvm::StringRef GetPluginDescriptionStatic();
+
+ static lldb_private::SymbolFile *
+ CreateInstance(lldb::ObjectFileSP objfile_sp);
+
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+ uint32_t CalculateAbilities() override;
+
+ void InitializeObject() override;
+
+ lldb::LanguageType ParseLanguage(CompileUnit &comp_unit) override {
+ return lldb::eLanguageTypeUnknown;
+ }
+
+ bool ParseHeader();
+
+ size_t ParseFunctions(CompileUnit &comp_unit) override;
+
+ size_t ParseObjects(CompileUnit &comp_unit);
+
+ bool ParseLineTable(CompileUnit &comp_unit) override { return false; }
+
+ bool ParseDebugMacros(CompileUnit &comp_unit) override { return false; }
+
+ bool ParseSupportFiles(CompileUnit &comp_unit,
+ SupportFileList &support_files) override {
+ return false;
+ }
+
+ size_t ParseTypes(CompileUnit &cu) override;
+
+ bool ParseImportedModules(
+ const SymbolContext &sc,
+ std::vector<lldb_private::SourceModule> &imported_modules) override {
+ return false;
+ }
+
+ size_t ParseBlocksRecursive(Function &func) override { return 0; }
+
+ size_t ParseVariablesForContext(const SymbolContext &sc) override;
+
+ uint32_t CalculateNumCompileUnits() override { return 0; }
+
+ lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index) override;
+
+ Type *ResolveTypeUID(lldb::user_id_t type_uid) override;
+ std::optional<ArrayInfo> GetDynamicArrayInfoForUID(
+ lldb::user_id_t type_uid,
+ const lldb_private::ExecutionContext *exe_ctx) override {
+ return std::nullopt;
+ }
+
+ bool CompleteType(CompilerType &compiler_type) override;
+
+ uint32_t ResolveSymbolContext(const lldb_private::Address &so_addr,
+ lldb::SymbolContextItem resolve_scope,
+ lldb_private::SymbolContext &sc) override;
+
+ void AddSymbols(Symtab &symtab) override;
+
+ void GetTypes(lldb_private::SymbolContextScope *sc_scope,
+ lldb::TypeClass type_mask,
+ lldb_private::TypeList &type_list) override {}
+
+ void FindTypes(const lldb_private::TypeQuery &match,
+ lldb_private::TypeResults &results) override;
+
+ void FindTypesByRegex(const lldb_private::RegularExpression &regex,
+ uint32_t max_matches, lldb_private::TypeMap &types);
+
+ void FindFunctions(const lldb_private::Module::LookupInfo &lookup_info,
+ const lldb_private::CompilerDeclContext &parent_decl_ctx,
+ bool include_inlines,
+ lldb_private::SymbolContextList &sc_list) override;
+
+ void FindFunctions(const lldb_private::RegularExpression &regex,
+ bool include_inlines,
+ lldb_private::SymbolContextList &sc_list) override;
+
+ void
+ FindGlobalVariables(lldb_private::ConstString name,
+ const lldb_private::CompilerDeclContext &parent_decl_ctx,
+ uint32_t max_matches,
+ lldb_private::VariableList &variables) override;
+
+ void FindGlobalVariables(const lldb_private::RegularExpression &regex,
+ uint32_t max_matches,
+ lldb_private::VariableList &variables) override;
+
+ enum TypeKind : uint32_t {
+ eUnknown = 0,
+ eInteger = 1,
+ eFloat = 2,
+ ePointer = 3,
+ eArray = 4,
+ eFunction = 5,
+ eStruct = 6,
+ eUnion = 7,
+ eEnum = 8,
+ eForward = 9,
+ eTypedef = 10,
+ eVolatile = 11,
+ eConst = 12,
+ eRestrict = 13,
+ eSlice = 14,
+ };
+
+private:
+ enum Flags : uint32_t {
+ eFlagCompress = (1u << 0),
+ eFlagNewFuncInfo = (1u << 1),
+ eFlagIdxSorted = (1u << 2),
+ eFlagDynStr = (1u << 3),
+ };
+
+ enum IntEncoding : uint32_t {
+ eSigned = 0x1,
+ eChar = 0x2,
+ eBool = 0x4,
+ eVarArgs = 0x8,
+ };
+
+ struct ctf_preamble_t {
+ uint16_t magic;
+ uint8_t version;
+ uint8_t flags;
+ };
+
+ struct ctf_header_t {
+ ctf_preamble_t preamble;
+ uint32_t parlabel;
+ uint32_t parname;
+ uint32_t lbloff;
+ uint32_t objtoff;
+ uint32_t funcoff;
+ uint32_t typeoff;
+ uint32_t stroff;
+ uint32_t strlen;
+ };
+
+ struct ctf_type_t {
+ uint32_t name;
+ uint32_t info;
+ union {
+ uint32_t size;
+ uint32_t type;
+ };
+ uint32_t lsizehi;
+ uint32_t lsizelo;
+ };
+
+ struct ctf_stype_t {
+ uint32_t name;
+ uint32_t info;
+ union {
+ uint32_t size;
+ uint32_t type;
+ };
+
+ bool IsLargeType() const { return size == 0xffff; }
+ uint32_t GetStructSize() const {
+ if (IsLargeType())
+ return sizeof(ctf_type_t);
+ return sizeof(ctf_stype_t);
+ }
+ uint32_t GetType() const { return type; }
+ uint32_t GetSize() const { return size; }
+ };
+
+ llvm::Expected<std::unique_ptr<CTFType>> ParseType(lldb::offset_t &offset,
+ lldb::user_id_t uid);
+
+ llvm::Expected<lldb::TypeSP> CreateType(CTFType *ctf_type);
+ llvm::Expected<lldb::TypeSP> CreateInteger(const CTFInteger &ctf_integer);
+ llvm::Expected<lldb::TypeSP> CreateModifier(const CTFModifier &ctf_modifier);
+ llvm::Expected<lldb::TypeSP> CreateTypedef(const CTFTypedef &ctf_typedef);
+ llvm::Expected<lldb::TypeSP> CreateArray(const CTFArray &ctf_array);
+ llvm::Expected<lldb::TypeSP> CreateEnum(const CTFEnum &ctf_enum);
+ llvm::Expected<lldb::TypeSP> CreateFunction(const CTFFunction &ctf_function);
+ llvm::Expected<lldb::TypeSP> CreateRecord(const CTFRecord &ctf_record);
+ llvm::Expected<lldb::TypeSP> CreateForward(const CTFForward &ctf_forward);
+
+ llvm::StringRef ReadString(lldb::offset_t offset) const;
+
+ std::vector<uint16_t> GetFieldSizes(lldb::offset_t field_offset,
+ uint32_t fields, uint32_t struct_size);
+
+ DataExtractor m_data;
+
+ /// The start offset of the CTF body into m_data. If the body is uncompressed,
+ /// m_data contains the header and the body and the body starts after the
+ /// header. If the body is compressed, m_data only contains the body and the
+ /// offset is zero.
+ lldb::offset_t m_body_offset = 0;
+
+ TypeSystemClang *m_ast;
+ lldb::CompUnitSP m_comp_unit_sp;
+
+ std::optional<ctf_header_t> m_header;
+
+ /// Parsed CTF types.
+ llvm::DenseMap<lldb::user_id_t, std::unique_ptr<CTFType>> m_ctf_types;
+
+ /// Parsed LLDB types.
+ llvm::DenseMap<lldb::user_id_t, lldb::TypeSP> m_types;
+
+ /// To complete types, we need a way to map (imcomplete) compiler types back
+ /// to parsed CTF types.
+ llvm::DenseMap<lldb::opaque_compiler_type_t, const CTFType *>
+ m_compiler_types;
+
+ std::vector<lldb::FunctionSP> m_functions;
+ std::vector<lldb::VariableSP> m_variables;
+
+ static constexpr uint16_t g_ctf_magic = 0xcff1;
+ static constexpr uint8_t g_ctf_version = 4;
+ static constexpr uint16_t g_ctf_field_threshold = 0x2000;
+};
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_CTF_SYMBOLFILECTF_H
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
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/JSON/SymbolFileJSON.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/JSON/SymbolFileJSON.cpp
new file mode 100644
index 000000000000..1f3ca27417e4
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/JSON/SymbolFileJSON.cpp
@@ -0,0 +1,105 @@
+//===-- SymbolFileJSON.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 "SymbolFileJSON.h"
+
+#include "Plugins/ObjectFile/JSON/ObjectFileJSON.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Symtab.h"
+#include "lldb/Symbol/TypeList.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/Timer.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+#include <memory>
+#include <optional>
+
+using namespace llvm;
+using namespace lldb;
+using namespace lldb_private;
+
+LLDB_PLUGIN_DEFINE(SymbolFileJSON)
+
+char SymbolFileJSON::ID;
+
+SymbolFileJSON::SymbolFileJSON(lldb::ObjectFileSP objfile_sp)
+ : SymbolFileCommon(std::move(objfile_sp)) {}
+
+void SymbolFileJSON::Initialize() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(), CreateInstance);
+}
+
+void SymbolFileJSON::Terminate() {
+ PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+llvm::StringRef SymbolFileJSON::GetPluginDescriptionStatic() {
+ return "Reads debug symbols from a JSON symbol table.";
+}
+
+SymbolFile *SymbolFileJSON::CreateInstance(ObjectFileSP objfile_sp) {
+ return new SymbolFileJSON(std::move(objfile_sp));
+}
+
+uint32_t SymbolFileJSON::CalculateAbilities() {
+ if (!m_objfile_sp || !llvm::isa<ObjectFileJSON>(*m_objfile_sp))
+ return 0;
+
+ return GlobalVariables | Functions;
+}
+
+uint32_t SymbolFileJSON::ResolveSymbolContext(const Address &so_addr,
+ SymbolContextItem resolve_scope,
+ SymbolContext &sc) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ if (m_objfile_sp->GetSymtab() == nullptr)
+ return 0;
+
+ uint32_t resolved_flags = 0;
+ if (resolve_scope & eSymbolContextSymbol) {
+ sc.symbol = m_objfile_sp->GetSymtab()->FindSymbolContainingFileAddress(
+ so_addr.GetFileAddress());
+ if (sc.symbol)
+ resolved_flags |= eSymbolContextSymbol;
+ }
+ return resolved_flags;
+}
+
+CompUnitSP SymbolFileJSON::ParseCompileUnitAtIndex(uint32_t idx) { return {}; }
+
+void SymbolFileJSON::GetTypes(SymbolContextScope *sc_scope, TypeClass type_mask,
+ lldb_private::TypeList &type_list) {}
+
+void SymbolFileJSON::AddSymbols(Symtab &symtab) {
+ if (!m_objfile_sp)
+ return;
+
+ Symtab *json_symtab = m_objfile_sp->GetSymtab();
+ if (!json_symtab)
+ return;
+
+ if (&symtab == json_symtab)
+ return;
+
+ // Merge the two symbol tables.
+ const size_t num_new_symbols = json_symtab->GetNumSymbols();
+ for (size_t i = 0; i < num_new_symbols; ++i) {
+ Symbol *s = json_symtab->SymbolAtIndex(i);
+ symtab.AddSymbol(*s);
+ }
+ symtab.Finalize();
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/JSON/SymbolFileJSON.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/JSON/SymbolFileJSON.h
new file mode 100644
index 000000000000..3dd33b3dc82f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/JSON/SymbolFileJSON.h
@@ -0,0 +1,110 @@
+//===-- SymbolFileJSON.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_JSON_SYMBOLFILEJSON_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_JSON_SYMBOLFILEJSON_H
+
+#include <map>
+#include <optional>
+#include <vector>
+
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/SymbolFile.h"
+
+namespace lldb_private {
+
+class SymbolFileJSON : public lldb_private::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); }
+ /// \}
+
+ SymbolFileJSON(lldb::ObjectFileSP objfile_sp);
+
+ static void Initialize();
+
+ static void Terminate();
+
+ static llvm::StringRef GetPluginNameStatic() { return "JSON"; }
+
+ static llvm::StringRef GetPluginDescriptionStatic();
+
+ static lldb_private::SymbolFile *
+ CreateInstance(lldb::ObjectFileSP objfile_sp);
+
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+ uint32_t CalculateAbilities() override;
+
+ lldb::LanguageType ParseLanguage(CompileUnit &comp_unit) override {
+ return lldb::eLanguageTypeUnknown;
+ }
+
+ size_t ParseFunctions(CompileUnit &comp_unit) override { return 0; }
+
+ bool ParseLineTable(CompileUnit &comp_unit) override { return false; }
+
+ bool ParseDebugMacros(CompileUnit &comp_unit) override { return false; }
+
+ bool ParseSupportFiles(CompileUnit &comp_unit,
+ SupportFileList &support_files) override {
+ return false;
+ }
+
+ size_t ParseTypes(CompileUnit &cu) override { return 0; }
+
+ bool ParseImportedModules(
+ const SymbolContext &sc,
+ std::vector<lldb_private::SourceModule> &imported_modules) override {
+ return false;
+ }
+
+ size_t ParseBlocksRecursive(Function &func) override { return 0; }
+
+ size_t ParseVariablesForContext(const SymbolContext &sc) override {
+ return 0;
+ }
+
+ uint32_t CalculateNumCompileUnits() override { return 0; }
+
+ lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index) override;
+
+ Type *ResolveTypeUID(lldb::user_id_t type_uid) override { return nullptr; }
+ std::optional<ArrayInfo> GetDynamicArrayInfoForUID(
+ lldb::user_id_t type_uid,
+ const lldb_private::ExecutionContext *exe_ctx) override {
+ return std::nullopt;
+ }
+
+ bool CompleteType(CompilerType &compiler_type) override { return false; }
+
+ uint32_t ResolveSymbolContext(const lldb_private::Address &so_addr,
+ lldb::SymbolContextItem resolve_scope,
+ lldb_private::SymbolContext &sc) override;
+
+ void GetTypes(lldb_private::SymbolContextScope *sc_scope,
+ lldb::TypeClass type_mask,
+ lldb_private::TypeList &type_list) override;
+
+ void AddSymbols(Symtab &symtab) override;
+
+private:
+ lldb::addr_t GetBaseFileAddress();
+
+ std::vector<std::pair<uint64_t, std::string>> m_symbols;
+};
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_JSON_SYMBOLFILEJSON_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.cpp
new file mode 100644
index 000000000000..3c10d4aa314b
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.cpp
@@ -0,0 +1,748 @@
+//===-- CodeViewRegisterMapping.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 "CodeViewRegisterMapping.h"
+
+#include "lldb/lldb-defines.h"
+
+#include "Plugins/Process/Utility/lldb-arm64-register-enums.h"
+#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
+
+using namespace lldb_private;
+
+static const uint32_t g_code_view_to_lldb_registers_arm64[] = {
+ LLDB_INVALID_REGNUM, // NONE
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ gpr_w0_arm64, // ARM64_W0, 10)
+ gpr_w1_arm64, // ARM64_W1, 11)
+ gpr_w2_arm64, // ARM64_W2, 12)
+ gpr_w3_arm64, // ARM64_W3, 13)
+ gpr_w4_arm64, // ARM64_W4, 14)
+ gpr_w5_arm64, // ARM64_W5, 15)
+ gpr_w6_arm64, // ARM64_W6, 16)
+ gpr_w7_arm64, // ARM64_W7, 17)
+ gpr_w8_arm64, // ARM64_W8, 18)
+ gpr_w9_arm64, // ARM64_W9, 19)
+ gpr_w10_arm64, // ARM64_W10, 20)
+ gpr_w11_arm64, // ARM64_W11, 21)
+ gpr_w12_arm64, // ARM64_W12, 22)
+ gpr_w13_arm64, // ARM64_W13, 23)
+ gpr_w14_arm64, // ARM64_W14, 24)
+ gpr_w15_arm64, // ARM64_W15, 25)
+ gpr_w16_arm64, // ARM64_W16, 26)
+ gpr_w17_arm64, // ARM64_W17, 27)
+ gpr_w18_arm64, // ARM64_W18, 28)
+ gpr_w19_arm64, // ARM64_W19, 29)
+ gpr_w20_arm64, // ARM64_W20, 30)
+ gpr_w21_arm64, // ARM64_W21, 31)
+ gpr_w22_arm64, // ARM64_W22, 32)
+ gpr_w23_arm64, // ARM64_W23, 33)
+ gpr_w24_arm64, // ARM64_W24, 34)
+ gpr_w25_arm64, // ARM64_W25, 35)
+ gpr_w26_arm64, // ARM64_W26, 36)
+ gpr_w27_arm64, // ARM64_W27, 37)
+ gpr_w28_arm64, // ARM64_W28, 38)
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ gpr_x0_arm64, // ARM64_X0, 50)
+ gpr_x1_arm64, // ARM64_X1, 51)
+ gpr_x2_arm64, // ARM64_X2, 52)
+ gpr_x3_arm64, // ARM64_X3, 53)
+ gpr_x4_arm64, // ARM64_X4, 54)
+ gpr_x5_arm64, // ARM64_X5, 55)
+ gpr_x6_arm64, // ARM64_X6, 56)
+ gpr_x7_arm64, // ARM64_X7, 57)
+ gpr_x8_arm64, // ARM64_X8, 58)
+ gpr_x9_arm64, // ARM64_X9, 59)
+ gpr_x10_arm64, // ARM64_X10, 60)
+ gpr_x11_arm64, // ARM64_X11, 61)
+ gpr_x12_arm64, // ARM64_X12, 62)
+ gpr_x13_arm64, // ARM64_X13, 63)
+ gpr_x14_arm64, // ARM64_X14, 64)
+ gpr_x15_arm64, // ARM64_X15, 65)
+ gpr_x16_arm64, // ARM64_X16, 66)
+ gpr_x17_arm64, // ARM64_X17, 67)
+ gpr_x18_arm64, // ARM64_X18, 68)
+ gpr_x19_arm64, // ARM64_X19, 69)
+ gpr_x20_arm64, // ARM64_X20, 70)
+ gpr_x21_arm64, // ARM64_X21, 71)
+ gpr_x22_arm64, // ARM64_X22, 72)
+ gpr_x23_arm64, // ARM64_X23, 73)
+ gpr_x24_arm64, // ARM64_X24, 74)
+ gpr_x25_arm64, // ARM64_X25, 75)
+ gpr_x26_arm64, // ARM64_X26, 76)
+ gpr_x27_arm64, // ARM64_X27, 77)
+ gpr_x28_arm64, // ARM64_X28, 78)
+ gpr_fp_arm64, // ARM64_FP, 79)
+ gpr_lr_arm64, // ARM64_LR, 80)
+ gpr_sp_arm64, // ARM64_SP, 81)
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ gpr_cpsr_arm64, // ARM64_NZCV, 90)
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_s0_arm64, // (ARM64_S0, 100)
+ fpu_s1_arm64, // (ARM64_S1, 101)
+ fpu_s2_arm64, // (ARM64_S2, 102)
+ fpu_s3_arm64, // (ARM64_S3, 103)
+ fpu_s4_arm64, // (ARM64_S4, 104)
+ fpu_s5_arm64, // (ARM64_S5, 105)
+ fpu_s6_arm64, // (ARM64_S6, 106)
+ fpu_s7_arm64, // (ARM64_S7, 107)
+ fpu_s8_arm64, // (ARM64_S8, 108)
+ fpu_s9_arm64, // (ARM64_S9, 109)
+ fpu_s10_arm64, // (ARM64_S10, 110)
+ fpu_s11_arm64, // (ARM64_S11, 111)
+ fpu_s12_arm64, // (ARM64_S12, 112)
+ fpu_s13_arm64, // (ARM64_S13, 113)
+ fpu_s14_arm64, // (ARM64_S14, 114)
+ fpu_s15_arm64, // (ARM64_S15, 115)
+ fpu_s16_arm64, // (ARM64_S16, 116)
+ fpu_s17_arm64, // (ARM64_S17, 117)
+ fpu_s18_arm64, // (ARM64_S18, 118)
+ fpu_s19_arm64, // (ARM64_S19, 119)
+ fpu_s20_arm64, // (ARM64_S20, 120)
+ fpu_s21_arm64, // (ARM64_S21, 121)
+ fpu_s22_arm64, // (ARM64_S22, 122)
+ fpu_s23_arm64, // (ARM64_S23, 123)
+ fpu_s24_arm64, // (ARM64_S24, 124)
+ fpu_s25_arm64, // (ARM64_S25, 125)
+ fpu_s26_arm64, // (ARM64_S26, 126)
+ fpu_s27_arm64, // (ARM64_S27, 127)
+ fpu_s28_arm64, // (ARM64_S28, 128)
+ fpu_s29_arm64, // (ARM64_S29, 129)
+ fpu_s30_arm64, // (ARM64_S30, 130)
+ fpu_s31_arm64, // (ARM64_S31, 131)
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_d0_arm64, // (ARM64_D0, 140)
+ fpu_d1_arm64, // (ARM64_D1, 141)
+ fpu_d2_arm64, // (ARM64_D2, 142)
+ fpu_d3_arm64, // (ARM64_D3, 143)
+ fpu_d4_arm64, // (ARM64_D4, 144)
+ fpu_d5_arm64, // (ARM64_D5, 145)
+ fpu_d6_arm64, // (ARM64_D6, 146)
+ fpu_d7_arm64, // (ARM64_D7, 147)
+ fpu_d8_arm64, // (ARM64_D8, 148)
+ fpu_d9_arm64, // (ARM64_D9, 149)
+ fpu_d10_arm64, // (ARM64_D10, 150)
+ fpu_d11_arm64, // (ARM64_D11, 151)
+ fpu_d12_arm64, // (ARM64_D12, 152)
+ fpu_d13_arm64, // (ARM64_D13, 153)
+ fpu_d14_arm64, // (ARM64_D14, 154)
+ fpu_d15_arm64, // (ARM64_D15, 155)
+ fpu_d16_arm64, // (ARM64_D16, 156)
+ fpu_d17_arm64, // (ARM64_D17, 157)
+ fpu_d18_arm64, // (ARM64_D18, 158)
+ fpu_d19_arm64, // (ARM64_D19, 159)
+ fpu_d20_arm64, // (ARM64_D20, 160)
+ fpu_d21_arm64, // (ARM64_D21, 161)
+ fpu_d22_arm64, // (ARM64_D22, 162)
+ fpu_d23_arm64, // (ARM64_D23, 163)
+ fpu_d24_arm64, // (ARM64_D24, 164)
+ fpu_d25_arm64, // (ARM64_D25, 165)
+ fpu_d26_arm64, // (ARM64_D26, 166)
+ fpu_d27_arm64, // (ARM64_D27, 167)
+ fpu_d28_arm64, // (ARM64_D28, 168)
+ fpu_d29_arm64, // (ARM64_D29, 169)
+ fpu_d30_arm64, // (ARM64_D30, 170)
+ fpu_d31_arm64, // (ARM64_D31, 171)
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_v0_arm64, // (ARM64_Q0, 180)
+ fpu_v1_arm64, // (ARM64_Q1, 181)
+ fpu_v2_arm64, // (ARM64_Q2, 182)
+ fpu_v3_arm64, // (ARM64_Q3, 183)
+ fpu_v4_arm64, // (ARM64_Q4, 184)
+ fpu_v5_arm64, // (ARM64_Q5, 185)
+ fpu_v6_arm64, // (ARM64_Q6, 186)
+ fpu_v7_arm64, // (ARM64_Q7, 187)
+ fpu_v8_arm64, // (ARM64_Q8, 188)
+ fpu_v9_arm64, // (ARM64_Q9, 189)
+ fpu_v10_arm64, // (ARM64_Q10, 190)
+ fpu_v11_arm64, // (ARM64_Q11, 191)
+ fpu_v12_arm64, // (ARM64_Q12, 192)
+ fpu_v13_arm64, // (ARM64_Q13, 193)
+ fpu_v14_arm64, // (ARM64_Q14, 194)
+ fpu_v15_arm64, // (ARM64_Q15, 195)
+ fpu_v16_arm64, // (ARM64_Q16, 196)
+ fpu_v17_arm64, // (ARM64_Q17, 197)
+ fpu_v18_arm64, // (ARM64_Q18, 198)
+ fpu_v19_arm64, // (ARM64_Q19, 199)
+ fpu_v20_arm64, // (ARM64_Q20, 200)
+ fpu_v21_arm64, // (ARM64_Q21, 201)
+ fpu_v22_arm64, // (ARM64_Q22, 202)
+ fpu_v23_arm64, // (ARM64_Q23, 203)
+ fpu_v24_arm64, // (ARM64_Q24, 204)
+ fpu_v25_arm64, // (ARM64_Q25, 205)
+ fpu_v26_arm64, // (ARM64_Q26, 206)
+ fpu_v27_arm64, // (ARM64_Q27, 207)
+ fpu_v28_arm64, // (ARM64_Q28, 208)
+ fpu_v29_arm64, // (ARM64_Q29, 209)
+ fpu_v30_arm64, // (ARM64_Q30, 210)
+ fpu_v31_arm64, // (ARM64_Q31, 211)
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_fpsr_arm64 // ARM64_FPSR, 220)
+};
+
+static const uint32_t g_code_view_to_lldb_registers_x86[] = {
+ LLDB_INVALID_REGNUM, // NONE
+ lldb_al_i386, // AL
+ lldb_cl_i386, // CL
+ lldb_dl_i386, // DL
+ lldb_bl_i386, // BL
+ lldb_ah_i386, // AH
+ lldb_ch_i386, // CH
+ lldb_dh_i386, // DH
+ lldb_bh_i386, // BH
+ lldb_ax_i386, // AX
+ lldb_cx_i386, // CX
+ lldb_dx_i386, // DX
+ lldb_bx_i386, // BX
+ lldb_sp_i386, // SP
+ lldb_bp_i386, // BP
+ lldb_si_i386, // SI
+ lldb_di_i386, // DI
+ lldb_eax_i386, // EAX
+ lldb_ecx_i386, // ECX
+ lldb_edx_i386, // EDX
+ lldb_ebx_i386, // EBX
+ lldb_esp_i386, // ESP
+ lldb_ebp_i386, // EBP
+ lldb_esi_i386, // ESI
+ lldb_edi_i386, // EDI
+ lldb_es_i386, // ES
+ lldb_cs_i386, // CS
+ lldb_ss_i386, // SS
+ lldb_ds_i386, // DS
+ lldb_fs_i386, // FS
+ lldb_gs_i386, // GS
+ LLDB_INVALID_REGNUM, // IP
+ LLDB_INVALID_REGNUM, // FLAGS
+ lldb_eip_i386, // EIP
+ lldb_eflags_i386, // EFLAGS
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, // TEMP
+ LLDB_INVALID_REGNUM, // TEMPH
+ LLDB_INVALID_REGNUM, // QUOTE
+ LLDB_INVALID_REGNUM, // PCDR3
+ LLDB_INVALID_REGNUM, // PCDR4
+ LLDB_INVALID_REGNUM, // PCDR5
+ LLDB_INVALID_REGNUM, // PCDR6
+ LLDB_INVALID_REGNUM, // PCDR7
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, // CR0
+ LLDB_INVALID_REGNUM, // CR1
+ LLDB_INVALID_REGNUM, // CR2
+ LLDB_INVALID_REGNUM, // CR3
+ LLDB_INVALID_REGNUM, // CR4
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ lldb_dr0_i386, // DR0
+ lldb_dr1_i386, // DR1
+ lldb_dr2_i386, // DR2
+ lldb_dr3_i386, // DR3
+ lldb_dr4_i386, // DR4
+ lldb_dr5_i386, // DR5
+ lldb_dr6_i386, // DR6
+ lldb_dr7_i386, // DR7
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, // GDTR
+ LLDB_INVALID_REGNUM, // GDTL
+ LLDB_INVALID_REGNUM, // IDTR
+ LLDB_INVALID_REGNUM, // IDTL
+ LLDB_INVALID_REGNUM, // LDTR
+ LLDB_INVALID_REGNUM, // TR
+ LLDB_INVALID_REGNUM, // PSEUDO1
+ LLDB_INVALID_REGNUM, // PSEUDO2
+ LLDB_INVALID_REGNUM, // PSEUDO3
+ LLDB_INVALID_REGNUM, // PSEUDO4
+ LLDB_INVALID_REGNUM, // PSEUDO5
+ LLDB_INVALID_REGNUM, // PSEUDO6
+ LLDB_INVALID_REGNUM, // PSEUDO7
+ LLDB_INVALID_REGNUM, // PSEUDO8
+ LLDB_INVALID_REGNUM, // PSEUDO9
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ lldb_st0_i386, // ST0
+ lldb_st1_i386, // ST1
+ lldb_st2_i386, // ST2
+ lldb_st3_i386, // ST3
+ lldb_st4_i386, // ST4
+ lldb_st5_i386, // ST5
+ lldb_st6_i386, // ST6
+ lldb_st7_i386, // ST7
+ LLDB_INVALID_REGNUM, // CTRL
+ LLDB_INVALID_REGNUM, // STAT
+ LLDB_INVALID_REGNUM, // TAG
+ LLDB_INVALID_REGNUM, // FPIP
+ LLDB_INVALID_REGNUM, // FPCS
+ LLDB_INVALID_REGNUM, // FPDO
+ LLDB_INVALID_REGNUM, // FPDS
+ LLDB_INVALID_REGNUM, // ISEM
+ LLDB_INVALID_REGNUM, // FPEIP
+ LLDB_INVALID_REGNUM, // FPEDO
+ lldb_mm0_i386, // MM0
+ lldb_mm1_i386, // MM1
+ lldb_mm2_i386, // MM2
+ lldb_mm3_i386, // MM3
+ lldb_mm4_i386, // MM4
+ lldb_mm5_i386, // MM5
+ lldb_mm6_i386, // MM6
+ lldb_mm7_i386, // MM7
+ lldb_xmm0_i386, // XMM0
+ lldb_xmm1_i386, // XMM1
+ lldb_xmm2_i386, // XMM2
+ lldb_xmm3_i386, // XMM3
+ lldb_xmm4_i386, // XMM4
+ lldb_xmm5_i386, // XMM5
+ lldb_xmm6_i386, // XMM6
+ lldb_xmm7_i386 // XMM7
+};
+
+static const uint32_t g_code_view_to_lldb_registers_x86_64[] = {
+ LLDB_INVALID_REGNUM, // NONE
+ lldb_al_x86_64, // AL
+ lldb_cl_x86_64, // CL
+ lldb_dl_x86_64, // DL
+ lldb_bl_x86_64, // BL
+ lldb_ah_x86_64, // AH
+ lldb_ch_x86_64, // CH
+ lldb_dh_x86_64, // DH
+ lldb_bh_x86_64, // BH
+ lldb_ax_x86_64, // AX
+ lldb_cx_x86_64, // CX
+ lldb_dx_x86_64, // DX
+ lldb_bx_x86_64, // BX
+ lldb_sp_x86_64, // SP
+ lldb_bp_x86_64, // BP
+ lldb_si_x86_64, // SI
+ lldb_di_x86_64, // DI
+ lldb_eax_x86_64, // EAX
+ lldb_ecx_x86_64, // ECX
+ lldb_edx_x86_64, // EDX
+ lldb_ebx_x86_64, // EBX
+ lldb_esp_x86_64, // ESP
+ lldb_ebp_x86_64, // EBP
+ lldb_esi_x86_64, // ESI
+ lldb_edi_x86_64, // EDI
+ lldb_es_x86_64, // ES
+ lldb_cs_x86_64, // CS
+ lldb_ss_x86_64, // SS
+ lldb_ds_x86_64, // DS
+ lldb_fs_x86_64, // FS
+ lldb_gs_x86_64, // GS
+ LLDB_INVALID_REGNUM, // IP
+ LLDB_INVALID_REGNUM, // FLAGS
+ LLDB_INVALID_REGNUM, // EIP
+ LLDB_INVALID_REGNUM, // EFLAGS
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, // TEMP
+ LLDB_INVALID_REGNUM, // TEMPH
+ LLDB_INVALID_REGNUM, // QUOTE
+ LLDB_INVALID_REGNUM, // PCDR3
+ LLDB_INVALID_REGNUM, // PCDR4
+ LLDB_INVALID_REGNUM, // PCDR5
+ LLDB_INVALID_REGNUM, // PCDR6
+ LLDB_INVALID_REGNUM, // PCDR7
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, // CR0
+ LLDB_INVALID_REGNUM, // CR1
+ LLDB_INVALID_REGNUM, // CR2
+ LLDB_INVALID_REGNUM, // CR3
+ LLDB_INVALID_REGNUM, // CR4
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ lldb_dr0_x86_64, // DR0
+ lldb_dr1_x86_64, // DR1
+ lldb_dr2_x86_64, // DR2
+ lldb_dr3_x86_64, // DR3
+ lldb_dr4_x86_64, // DR4
+ lldb_dr5_x86_64, // DR5
+ lldb_dr6_x86_64, // DR6
+ lldb_dr7_x86_64, // DR7
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, // GDTR
+ LLDB_INVALID_REGNUM, // GDTL
+ LLDB_INVALID_REGNUM, // IDTR
+ LLDB_INVALID_REGNUM, // IDTL
+ LLDB_INVALID_REGNUM, // LDTR
+ LLDB_INVALID_REGNUM, // TR
+ LLDB_INVALID_REGNUM, // PSEUDO1
+ LLDB_INVALID_REGNUM, // PSEUDO2
+ LLDB_INVALID_REGNUM, // PSEUDO3
+ LLDB_INVALID_REGNUM, // PSEUDO4
+ LLDB_INVALID_REGNUM, // PSEUDO5
+ LLDB_INVALID_REGNUM, // PSEUDO6
+ LLDB_INVALID_REGNUM, // PSEUDO7
+ LLDB_INVALID_REGNUM, // PSEUDO8
+ LLDB_INVALID_REGNUM, // PSEUDO9
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ lldb_st0_x86_64, // ST0
+ lldb_st1_x86_64, // ST1
+ lldb_st2_x86_64, // ST2
+ lldb_st3_x86_64, // ST3
+ lldb_st4_x86_64, // ST4
+ lldb_st5_x86_64, // ST5
+ lldb_st6_x86_64, // ST6
+ lldb_st7_x86_64, // ST7
+ LLDB_INVALID_REGNUM, // CTRL
+ LLDB_INVALID_REGNUM, // STAT
+ LLDB_INVALID_REGNUM, // TAG
+ LLDB_INVALID_REGNUM, // FPIP
+ LLDB_INVALID_REGNUM, // FPCS
+ LLDB_INVALID_REGNUM, // FPDO
+ LLDB_INVALID_REGNUM, // FPDS
+ LLDB_INVALID_REGNUM, // ISEM
+ LLDB_INVALID_REGNUM, // FPEIP
+ LLDB_INVALID_REGNUM, // FPEDO
+ lldb_mm0_x86_64, // MM0
+ lldb_mm1_x86_64, // MM1
+ lldb_mm2_x86_64, // MM2
+ lldb_mm3_x86_64, // MM3
+ lldb_mm4_x86_64, // MM4
+ lldb_mm5_x86_64, // MM5
+ lldb_mm6_x86_64, // MM6
+ lldb_mm7_x86_64, // MM7
+ lldb_xmm0_x86_64, // XMM0
+ lldb_xmm1_x86_64, // XMM1
+ lldb_xmm2_x86_64, // XMM2
+ lldb_xmm3_x86_64, // XMM3
+ lldb_xmm4_x86_64, // XMM4
+ lldb_xmm5_x86_64, // XMM5
+ lldb_xmm6_x86_64, // XMM6
+ lldb_xmm7_x86_64, // XMM7
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM,
+ lldb_mxcsr_x86_64, // MXCSR
+ LLDB_INVALID_REGNUM, // EDXEAX
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, // EMM0L
+ LLDB_INVALID_REGNUM, // EMM1L
+ LLDB_INVALID_REGNUM, // EMM2L
+ LLDB_INVALID_REGNUM, // EMM3L
+ LLDB_INVALID_REGNUM, // EMM4L
+ LLDB_INVALID_REGNUM, // EMM5L
+ LLDB_INVALID_REGNUM, // EMM6L
+ LLDB_INVALID_REGNUM, // EMM7L
+ LLDB_INVALID_REGNUM, // EMM0H
+ LLDB_INVALID_REGNUM, // EMM1H
+ LLDB_INVALID_REGNUM, // EMM2H
+ LLDB_INVALID_REGNUM, // EMM3H
+ LLDB_INVALID_REGNUM, // EMM4H
+ LLDB_INVALID_REGNUM, // EMM5H
+ LLDB_INVALID_REGNUM, // EMM6H
+ LLDB_INVALID_REGNUM, // EMM7H
+ LLDB_INVALID_REGNUM, // MM00
+ LLDB_INVALID_REGNUM, // MM01
+ LLDB_INVALID_REGNUM, // MM10
+ LLDB_INVALID_REGNUM, // MM11
+ LLDB_INVALID_REGNUM, // MM20
+ LLDB_INVALID_REGNUM, // MM21
+ LLDB_INVALID_REGNUM, // MM30
+ LLDB_INVALID_REGNUM, // MM31
+ LLDB_INVALID_REGNUM, // MM40
+ LLDB_INVALID_REGNUM, // MM41
+ LLDB_INVALID_REGNUM, // MM50
+ LLDB_INVALID_REGNUM, // MM51
+ LLDB_INVALID_REGNUM, // MM60
+ LLDB_INVALID_REGNUM, // MM61
+ LLDB_INVALID_REGNUM, // MM70
+ LLDB_INVALID_REGNUM, // MM71
+ lldb_xmm8_x86_64, // XMM8
+ lldb_xmm9_x86_64, // XMM9
+ lldb_xmm10_x86_64, // XMM10
+ lldb_xmm11_x86_64, // XMM11
+ lldb_xmm12_x86_64, // XMM12
+ lldb_xmm13_x86_64, // XMM13
+ lldb_xmm14_x86_64, // XMM14
+ lldb_xmm15_x86_64, // XMM15
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM,
+ lldb_sil_x86_64, // SIL
+ lldb_dil_x86_64, // DIL
+ lldb_bpl_x86_64, // BPL
+ lldb_spl_x86_64, // SPL
+ lldb_rax_x86_64, // RAX
+ lldb_rbx_x86_64, // RBX
+ lldb_rcx_x86_64, // RCX
+ lldb_rdx_x86_64, // RDX
+ lldb_rsi_x86_64, // RSI
+ lldb_rdi_x86_64, // RDI
+ lldb_rbp_x86_64, // RBP
+ lldb_rsp_x86_64, // RSP
+ lldb_r8_x86_64, // R8
+ lldb_r9_x86_64, // R9
+ lldb_r10_x86_64, // R10
+ lldb_r11_x86_64, // R11
+ lldb_r12_x86_64, // R12
+ lldb_r13_x86_64, // R13
+ lldb_r14_x86_64, // R14
+ lldb_r15_x86_64, // R15
+ lldb_r8l_x86_64, // R8B
+ lldb_r9l_x86_64, // R9B
+ lldb_r10l_x86_64, // R10B
+ lldb_r11l_x86_64, // R11B
+ lldb_r12l_x86_64, // R12B
+ lldb_r13l_x86_64, // R13B
+ lldb_r14l_x86_64, // R14B
+ lldb_r15l_x86_64, // R15B
+ lldb_r8w_x86_64, // R8W
+ lldb_r9w_x86_64, // R9W
+ lldb_r10w_x86_64, // R10W
+ lldb_r11w_x86_64, // R11W
+ lldb_r12w_x86_64, // R12W
+ lldb_r13w_x86_64, // R13W
+ lldb_r14w_x86_64, // R14W
+ lldb_r15w_x86_64, // R15W
+ lldb_r8d_x86_64, // R8D
+ lldb_r9d_x86_64, // R9D
+ lldb_r10d_x86_64, // R10D
+ lldb_r11d_x86_64, // R11D
+ lldb_r12d_x86_64, // R12D
+ lldb_r13d_x86_64, // R13D
+ lldb_r14d_x86_64, // R14D
+ lldb_r15d_x86_64, // R15D
+ lldb_ymm0_x86_64, // AMD64_YMM0
+ lldb_ymm1_x86_64, // AMD64_YMM1
+ lldb_ymm2_x86_64, // AMD64_YMM2
+ lldb_ymm3_x86_64, // AMD64_YMM3
+ lldb_ymm4_x86_64, // AMD64_YMM4
+ lldb_ymm5_x86_64, // AMD64_YMM5
+ lldb_ymm6_x86_64, // AMD64_YMM6
+ lldb_ymm7_x86_64, // AMD64_YMM7
+ lldb_ymm8_x86_64, // AMD64_YMM8
+ lldb_ymm9_x86_64, // AMD64_YMM9
+ lldb_ymm10_x86_64, // AMD64_YMM10
+ lldb_ymm11_x86_64, // AMD64_YMM11
+ lldb_ymm12_x86_64, // AMD64_YMM12
+ lldb_ymm13_x86_64, // AMD64_YMM13
+ lldb_ymm14_x86_64, // AMD64_YMM14
+ lldb_ymm15_x86_64, // AMD64_YMM15
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ lldb_bnd0_x86_64, // BND0
+ lldb_bnd1_x86_64, // BND1
+ lldb_bnd2_x86_64 // BND2
+};
+
+uint32_t lldb_private::npdb::GetLLDBRegisterNumber(
+ llvm::Triple::ArchType arch_type, llvm::codeview::RegisterId register_id) {
+ switch (arch_type) {
+ case llvm::Triple::aarch64:
+ if (static_cast<uint16_t>(register_id) <
+ sizeof(g_code_view_to_lldb_registers_arm64) /
+ sizeof(g_code_view_to_lldb_registers_arm64[0]))
+ return g_code_view_to_lldb_registers_arm64[static_cast<uint16_t>(
+ register_id)];
+
+ return LLDB_INVALID_REGNUM;
+ case llvm::Triple::x86:
+ if (static_cast<uint16_t>(register_id) <
+ sizeof(g_code_view_to_lldb_registers_x86) /
+ sizeof(g_code_view_to_lldb_registers_x86[0]))
+ return g_code_view_to_lldb_registers_x86[static_cast<uint16_t>(
+ register_id)];
+
+ switch (register_id) {
+ case llvm::codeview::RegisterId::MXCSR:
+ return lldb_mxcsr_i386;
+ case llvm::codeview::RegisterId::BND0:
+ return lldb_bnd0_i386;
+ case llvm::codeview::RegisterId::BND1:
+ return lldb_bnd1_i386;
+ case llvm::codeview::RegisterId::BND2:
+ return lldb_bnd2_i386;
+ default:
+ return LLDB_INVALID_REGNUM;
+ }
+ case llvm::Triple::x86_64:
+ if (static_cast<uint16_t>(register_id) <
+ sizeof(g_code_view_to_lldb_registers_x86_64) /
+ sizeof(g_code_view_to_lldb_registers_x86_64[0]))
+ return g_code_view_to_lldb_registers_x86_64[static_cast<uint16_t>(
+ register_id)];
+
+ return LLDB_INVALID_REGNUM;
+ default:
+ return LLDB_INVALID_REGNUM;
+ }
+}
+
+uint32_t
+lldb_private::npdb::GetRegisterSize(llvm::codeview::RegisterId register_id) {
+ switch(register_id) {
+ case llvm::codeview::RegisterId::AL:
+ case llvm::codeview::RegisterId::BL:
+ case llvm::codeview::RegisterId::CL:
+ case llvm::codeview::RegisterId::DL:
+ case llvm::codeview::RegisterId::AH:
+ case llvm::codeview::RegisterId::BH:
+ case llvm::codeview::RegisterId::CH:
+ case llvm::codeview::RegisterId::DH:
+ case llvm::codeview::RegisterId::SIL:
+ case llvm::codeview::RegisterId::DIL:
+ case llvm::codeview::RegisterId::BPL:
+ case llvm::codeview::RegisterId::SPL:
+ case llvm::codeview::RegisterId::R8B:
+ case llvm::codeview::RegisterId::R9B:
+ case llvm::codeview::RegisterId::R10B:
+ case llvm::codeview::RegisterId::R11B:
+ case llvm::codeview::RegisterId::R12B:
+ case llvm::codeview::RegisterId::R13B:
+ case llvm::codeview::RegisterId::R14B:
+ case llvm::codeview::RegisterId::R15B:
+ return 1;
+ case llvm::codeview::RegisterId::AX:
+ case llvm::codeview::RegisterId::BX:
+ case llvm::codeview::RegisterId::CX:
+ case llvm::codeview::RegisterId::DX:
+ case llvm::codeview::RegisterId::SP:
+ case llvm::codeview::RegisterId::BP:
+ case llvm::codeview::RegisterId::SI:
+ case llvm::codeview::RegisterId::DI:
+ case llvm::codeview::RegisterId::R8W:
+ case llvm::codeview::RegisterId::R9W:
+ case llvm::codeview::RegisterId::R10W:
+ case llvm::codeview::RegisterId::R11W:
+ case llvm::codeview::RegisterId::R12W:
+ case llvm::codeview::RegisterId::R13W:
+ case llvm::codeview::RegisterId::R14W:
+ case llvm::codeview::RegisterId::R15W:
+ return 2;
+ case llvm::codeview::RegisterId::EAX:
+ case llvm::codeview::RegisterId::EBX:
+ case llvm::codeview::RegisterId::ECX:
+ case llvm::codeview::RegisterId::EDX:
+ case llvm::codeview::RegisterId::ESP:
+ case llvm::codeview::RegisterId::EBP:
+ case llvm::codeview::RegisterId::ESI:
+ case llvm::codeview::RegisterId::EDI:
+ case llvm::codeview::RegisterId::R8D:
+ case llvm::codeview::RegisterId::R9D:
+ case llvm::codeview::RegisterId::R10D:
+ case llvm::codeview::RegisterId::R11D:
+ case llvm::codeview::RegisterId::R12D:
+ case llvm::codeview::RegisterId::R13D:
+ case llvm::codeview::RegisterId::R14D:
+ case llvm::codeview::RegisterId::R15D:
+ return 4;
+ case llvm::codeview::RegisterId::RAX:
+ case llvm::codeview::RegisterId::RBX:
+ case llvm::codeview::RegisterId::RCX:
+ case llvm::codeview::RegisterId::RDX:
+ case llvm::codeview::RegisterId::RSI:
+ case llvm::codeview::RegisterId::RDI:
+ case llvm::codeview::RegisterId::RBP:
+ case llvm::codeview::RegisterId::RSP:
+ case llvm::codeview::RegisterId::R8:
+ case llvm::codeview::RegisterId::R9:
+ case llvm::codeview::RegisterId::R10:
+ case llvm::codeview::RegisterId::R11:
+ case llvm::codeview::RegisterId::R12:
+ case llvm::codeview::RegisterId::R13:
+ case llvm::codeview::RegisterId::R14:
+ case llvm::codeview::RegisterId::R15:
+ return 8;
+ case llvm::codeview::RegisterId::XMM0:
+ case llvm::codeview::RegisterId::XMM1:
+ case llvm::codeview::RegisterId::XMM2:
+ case llvm::codeview::RegisterId::XMM3:
+ case llvm::codeview::RegisterId::XMM4:
+ case llvm::codeview::RegisterId::XMM5:
+ case llvm::codeview::RegisterId::XMM6:
+ case llvm::codeview::RegisterId::XMM7:
+ case llvm::codeview::RegisterId::XMM8:
+ case llvm::codeview::RegisterId::XMM9:
+ case llvm::codeview::RegisterId::XMM10:
+ case llvm::codeview::RegisterId::XMM11:
+ case llvm::codeview::RegisterId::XMM12:
+ case llvm::codeview::RegisterId::XMM13:
+ case llvm::codeview::RegisterId::XMM14:
+ case llvm::codeview::RegisterId::XMM15:
+ return 16;
+ default:
+ return 0;
+ }
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.h
new file mode 100644
index 000000000000..4717fdcf11e3
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.h
@@ -0,0 +1,25 @@
+//===-- CodeViewRegisterMapping.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_NATIVEPDB_CODEVIEWREGISTERMAPPING_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_CODEVIEWREGISTERMAPPING_H
+
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/TargetParser/Triple.h"
+
+namespace lldb_private {
+namespace npdb {
+
+uint32_t GetLLDBRegisterNumber(llvm::Triple::ArchType arch_type,
+ llvm::codeview::RegisterId register_id);
+uint32_t GetRegisterSize(llvm::codeview::RegisterId register_id);
+
+} // namespace npdb
+} // namespace lldb_private
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp
new file mode 100644
index 000000000000..25d04f999ad6
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp
@@ -0,0 +1,248 @@
+//===-- CompileUnitIndex.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 "CompileUnitIndex.h"
+
+#include "PdbIndex.h"
+#include "PdbUtil.h"
+
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
+#include "llvm/DebugInfo/PDB/Native/NamedStreamMap.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/Support/Path.h"
+
+#include "lldb/Utility/LLDBAssert.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::npdb;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+static bool IsMainFile(llvm::StringRef main, llvm::StringRef other) {
+ if (main == other)
+ return true;
+
+ // If the files refer to the local file system, we can just ask the file
+ // system if they're equivalent. But if the source isn't present on disk
+ // then we still want to try.
+ if (llvm::sys::fs::equivalent(main, other))
+ return true;
+
+ llvm::SmallString<64> normalized(other);
+ llvm::sys::path::native(normalized);
+ return main.equals_insensitive(normalized);
+}
+
+static void ParseCompile3(const CVSymbol &sym, CompilandIndexItem &cci) {
+ cci.m_compile_opts.emplace();
+ llvm::cantFail(
+ SymbolDeserializer::deserializeAs<Compile3Sym>(sym, *cci.m_compile_opts));
+}
+
+static void ParseObjname(const CVSymbol &sym, CompilandIndexItem &cci) {
+ cci.m_obj_name.emplace();
+ llvm::cantFail(
+ SymbolDeserializer::deserializeAs<ObjNameSym>(sym, *cci.m_obj_name));
+}
+
+static void ParseBuildInfo(PdbIndex &index, const CVSymbol &sym,
+ CompilandIndexItem &cci) {
+ BuildInfoSym bis(SymbolRecordKind::BuildInfoSym);
+ llvm::cantFail(SymbolDeserializer::deserializeAs<BuildInfoSym>(sym, bis));
+
+ // S_BUILDINFO just points to an LF_BUILDINFO in the IPI stream. Let's do
+ // a little extra work to pull out the LF_BUILDINFO.
+ LazyRandomTypeCollection &types = index.ipi().typeCollection();
+ std::optional<CVType> cvt = types.tryGetType(bis.BuildId);
+
+ if (!cvt || cvt->kind() != LF_BUILDINFO)
+ return;
+
+ BuildInfoRecord bir;
+ llvm::cantFail(TypeDeserializer::deserializeAs<BuildInfoRecord>(*cvt, bir));
+ cci.m_build_info.assign(bir.ArgIndices.begin(), bir.ArgIndices.end());
+}
+
+static void ParseExtendedInfo(PdbIndex &index, CompilandIndexItem &item) {
+ const CVSymbolArray &syms = item.m_debug_stream.getSymbolArray();
+
+ // This is a private function, it shouldn't be called if the information
+ // has already been parsed.
+ lldbassert(!item.m_obj_name);
+ lldbassert(!item.m_compile_opts);
+ lldbassert(item.m_build_info.empty());
+
+ // We're looking for 3 things. S_COMPILE3, S_OBJNAME, and S_BUILDINFO.
+ int found = 0;
+ for (const CVSymbol &sym : syms) {
+ switch (sym.kind()) {
+ case S_COMPILE3:
+ ParseCompile3(sym, item);
+ break;
+ case S_OBJNAME:
+ ParseObjname(sym, item);
+ break;
+ case S_BUILDINFO:
+ ParseBuildInfo(index, sym, item);
+ break;
+ default:
+ continue;
+ }
+ if (++found >= 3)
+ break;
+ }
+}
+
+static void ParseInlineeLineTableForCompileUnit(CompilandIndexItem &item) {
+ for (const auto &ss : item.m_debug_stream.getSubsectionsArray()) {
+ if (ss.kind() != DebugSubsectionKind::InlineeLines)
+ continue;
+
+ DebugInlineeLinesSubsectionRef inlinee_lines;
+ llvm::BinaryStreamReader reader(ss.getRecordData());
+ if (llvm::Error error = inlinee_lines.initialize(reader)) {
+ consumeError(std::move(error));
+ continue;
+ }
+
+ for (const InlineeSourceLine &Line : inlinee_lines) {
+ item.m_inline_map[Line.Header->Inlinee] = Line;
+ }
+ }
+}
+
+CompilandIndexItem::CompilandIndexItem(
+ PdbCompilandId id, llvm::pdb::ModuleDebugStreamRef debug_stream,
+ llvm::pdb::DbiModuleDescriptor descriptor)
+ : m_id(id), m_debug_stream(std::move(debug_stream)),
+ m_module_descriptor(std::move(descriptor)) {}
+
+CompilandIndexItem &CompileUnitIndex::GetOrCreateCompiland(uint16_t modi) {
+ auto result = m_comp_units.try_emplace(modi, nullptr);
+ if (!result.second)
+ return *result.first->second;
+
+ // Find the module list and load its debug information stream and cache it
+ // since we need to use it for almost all interesting operations.
+ const DbiModuleList &modules = m_index.dbi().modules();
+ llvm::pdb::DbiModuleDescriptor descriptor = modules.getModuleDescriptor(modi);
+ uint16_t stream = descriptor.getModuleStreamIndex();
+ std::unique_ptr<llvm::msf::MappedBlockStream> stream_data =
+ m_index.pdb().createIndexedStream(stream);
+
+
+ std::unique_ptr<CompilandIndexItem>& cci = result.first->second;
+
+ if (!stream_data) {
+ llvm::pdb::ModuleDebugStreamRef debug_stream(descriptor, nullptr);
+ cci = std::make_unique<CompilandIndexItem>(PdbCompilandId{ modi }, debug_stream, std::move(descriptor));
+ return *cci;
+ }
+
+ llvm::pdb::ModuleDebugStreamRef debug_stream(descriptor,
+ std::move(stream_data));
+
+ cantFail(debug_stream.reload());
+
+ cci = std::make_unique<CompilandIndexItem>(
+ PdbCompilandId{modi}, std::move(debug_stream), std::move(descriptor));
+ ParseExtendedInfo(m_index, *cci);
+ ParseInlineeLineTableForCompileUnit(*cci);
+
+ auto strings = m_index.pdb().getStringTable();
+ if (strings) {
+ cci->m_strings.initialize(cci->m_debug_stream.getSubsectionsArray());
+ cci->m_strings.setStrings(strings->getStringTable());
+ } else {
+ consumeError(strings.takeError());
+ }
+
+ // We want the main source file to always comes first. Note that we can't
+ // just push_back the main file onto the front because `GetMainSourceFile`
+ // computes it in such a way that it doesn't own the resulting memory. So we
+ // have to iterate the module file list comparing each one to the main file
+ // name until we find it, and we can cache that one since the memory is backed
+ // by a contiguous chunk inside the mapped PDB.
+ llvm::SmallString<64> main_file = GetMainSourceFile(*cci);
+ std::string s = std::string(main_file.str());
+ llvm::sys::path::native(main_file);
+
+ uint32_t file_count = modules.getSourceFileCount(modi);
+ cci->m_file_list.reserve(file_count);
+ bool found_main_file = false;
+ for (llvm::StringRef file : modules.source_files(modi)) {
+ if (!found_main_file && IsMainFile(main_file, file)) {
+ cci->m_file_list.insert(cci->m_file_list.begin(), file);
+ found_main_file = true;
+ continue;
+ }
+ cci->m_file_list.push_back(file);
+ }
+
+ return *cci;
+}
+
+const CompilandIndexItem *CompileUnitIndex::GetCompiland(uint16_t modi) const {
+ auto iter = m_comp_units.find(modi);
+ if (iter == m_comp_units.end())
+ return nullptr;
+ return iter->second.get();
+}
+
+CompilandIndexItem *CompileUnitIndex::GetCompiland(uint16_t modi) {
+ auto iter = m_comp_units.find(modi);
+ if (iter == m_comp_units.end())
+ return nullptr;
+ return iter->second.get();
+}
+
+llvm::SmallString<64>
+CompileUnitIndex::GetMainSourceFile(const CompilandIndexItem &item) const {
+ // LF_BUILDINFO contains a list of arg indices which point to LF_STRING_ID
+ // records in the IPI stream. The order of the arg indices is as follows:
+ // [0] - working directory where compiler was invoked.
+ // [1] - absolute path to compiler binary
+ // [2] - source file name
+ // [3] - path to compiler generated PDB (the /Zi PDB, although this entry gets
+ // added even when using /Z7)
+ // [4] - full command line invocation.
+ //
+ // We need to form the path [0]\[2] to generate the full path to the main
+ // file.source
+ if (item.m_build_info.size() < 3)
+ return {""};
+
+ LazyRandomTypeCollection &types = m_index.ipi().typeCollection();
+
+ StringIdRecord working_dir;
+ StringIdRecord file_name;
+ CVType dir_cvt = types.getType(item.m_build_info[0]);
+ CVType file_cvt = types.getType(item.m_build_info[2]);
+ llvm::cantFail(
+ TypeDeserializer::deserializeAs<StringIdRecord>(dir_cvt, working_dir));
+ llvm::cantFail(
+ TypeDeserializer::deserializeAs<StringIdRecord>(file_cvt, file_name));
+
+ llvm::sys::path::Style style = working_dir.String.starts_with("/")
+ ? llvm::sys::path::Style::posix
+ : llvm::sys::path::Style::windows;
+ if (llvm::sys::path::is_absolute(file_name.String, style))
+ return file_name.String;
+
+ llvm::SmallString<64> absolute_path = working_dir.String;
+ llvm::sys::path::append(absolute_path, file_name.String);
+ return absolute_path;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h
new file mode 100644
index 000000000000..3e6766a204dd
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h
@@ -0,0 +1,108 @@
+//===-- CompileUnitIndex.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_NATIVEPDB_COMPILEUNITINDEX_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_COMPILEUNITINDEX_H
+
+#include "lldb/Utility/RangeMap.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/IntervalMap.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
+#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
+#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
+#include "llvm/DebugInfo/PDB/PDBTypes.h"
+
+#include "PdbSymUid.h"
+
+#include <map>
+#include <memory>
+#include <optional>
+
+namespace lldb_private {
+
+namespace npdb {
+class PdbIndex;
+
+/// Represents a single compile unit. This class is useful for collecting the
+/// important accessors and information about a compile unit from disparate
+/// parts of the PDB into a single place, simplifying acess to compile unit
+/// information for the callers.
+struct CompilandIndexItem {
+ CompilandIndexItem(PdbCompilandId m_id,
+ llvm::pdb::ModuleDebugStreamRef debug_stream,
+ llvm::pdb::DbiModuleDescriptor descriptor);
+
+ // index of this compile unit.
+ PdbCompilandId m_id;
+
+ // debug stream.
+ llvm::pdb::ModuleDebugStreamRef m_debug_stream;
+
+ // dbi module descriptor.
+ llvm::pdb::DbiModuleDescriptor m_module_descriptor;
+
+ llvm::codeview::StringsAndChecksumsRef m_strings;
+
+ // List of files which contribute to this compiland.
+ std::vector<llvm::StringRef> m_file_list;
+
+ // Maps virtual address to global symbol id, which can then be used to
+ // locate the exact compile unit and offset of the symbol. Note that this
+ // is intentionally an ordered map so that we can find all symbols up to a
+ // given starting address.
+ std::map<lldb::addr_t, PdbSymUid> m_symbols_by_va;
+
+ // S_COMPILE3 sym describing compilation settings for the module.
+ std::optional<llvm::codeview::Compile3Sym> m_compile_opts;
+
+ // S_OBJNAME sym describing object name.
+ std::optional<llvm::codeview::ObjNameSym> m_obj_name;
+
+ // LF_BUILDINFO sym describing source file name, working directory,
+ // command line, etc. This usually contains exactly 5 items which
+ // are references to other strings.
+ llvm::SmallVector<llvm::codeview::TypeIndex, 5> m_build_info;
+
+ // Inlinee lines table in this compile unit.
+ std::map<llvm::codeview::TypeIndex, llvm::codeview::InlineeSourceLine>
+ m_inline_map;
+
+ // It's the line table parsed from DEBUG_S_LINES sections, mapping the file
+ // address range to file index and source line number.
+ using GlobalLineTable =
+ lldb_private::RangeDataVector<lldb::addr_t, uint32_t,
+ std::pair<uint32_t, uint32_t>>;
+ GlobalLineTable m_global_line_table;
+};
+
+/// Indexes information about all compile units. This is really just a map of
+/// global compile unit index to |CompilandIndexItem| structures.
+class CompileUnitIndex {
+ PdbIndex &m_index;
+ llvm::DenseMap<uint16_t, std::unique_ptr<CompilandIndexItem>> m_comp_units;
+
+public:
+ explicit CompileUnitIndex(PdbIndex &index) : m_index(index) {}
+
+ CompilandIndexItem &GetOrCreateCompiland(uint16_t modi);
+
+ const CompilandIndexItem *GetCompiland(uint16_t modi) const;
+
+ CompilandIndexItem *GetCompiland(uint16_t modi);
+
+ llvm::SmallString<64> GetMainSourceFile(const CompilandIndexItem &item) const;
+};
+} // namespace npdb
+} // namespace lldb_private
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp
new file mode 100644
index 000000000000..75adf7302f00
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp
@@ -0,0 +1,300 @@
+//===-- DWARFLocationExpression.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 "DWARFLocationExpression.h"
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/StreamBuffer.h"
+
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/Support/Endian.h"
+
+#include "PdbUtil.h"
+#include "CodeViewRegisterMapping.h"
+#include "PdbFPOProgramToDWARFExpression.h"
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::npdb;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+uint32_t GetGenericRegisterNumber(llvm::codeview::RegisterId register_id) {
+ if (register_id == llvm::codeview::RegisterId::VFRAME)
+ return LLDB_REGNUM_GENERIC_FP;
+
+ return LLDB_INVALID_REGNUM;
+}
+
+static uint32_t GetRegisterNumber(llvm::Triple::ArchType arch_type,
+ llvm::codeview::RegisterId register_id,
+ RegisterKind &register_kind) {
+ register_kind = eRegisterKindLLDB;
+ uint32_t reg_num = GetLLDBRegisterNumber(arch_type, register_id);
+ if (reg_num != LLDB_INVALID_REGNUM)
+ return reg_num;
+
+ register_kind = eRegisterKindGeneric;
+ return GetGenericRegisterNumber(register_id);
+}
+
+static bool IsSimpleTypeSignedInteger(SimpleTypeKind kind) {
+ switch (kind) {
+ case SimpleTypeKind::Int128:
+ case SimpleTypeKind::Int64:
+ case SimpleTypeKind::Int64Quad:
+ case SimpleTypeKind::Int32:
+ case SimpleTypeKind::Int32Long:
+ case SimpleTypeKind::Int16:
+ case SimpleTypeKind::Int16Short:
+ case SimpleTypeKind::Float128:
+ case SimpleTypeKind::Float80:
+ case SimpleTypeKind::Float64:
+ case SimpleTypeKind::Float32:
+ case SimpleTypeKind::Float16:
+ case SimpleTypeKind::NarrowCharacter:
+ case SimpleTypeKind::SignedCharacter:
+ case SimpleTypeKind::SByte:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static std::pair<size_t, bool> GetIntegralTypeInfo(TypeIndex ti,
+ TpiStream &tpi) {
+ if (ti.isSimple()) {
+ SimpleTypeKind stk = ti.getSimpleKind();
+ return {GetTypeSizeForSimpleKind(stk), IsSimpleTypeSignedInteger(stk)};
+ }
+
+ CVType cvt = tpi.getType(ti);
+ switch (cvt.kind()) {
+ case LF_MODIFIER: {
+ ModifierRecord mfr;
+ llvm::cantFail(TypeDeserializer::deserializeAs<ModifierRecord>(cvt, mfr));
+ return GetIntegralTypeInfo(mfr.ModifiedType, tpi);
+ }
+ case LF_POINTER: {
+ PointerRecord pr;
+ llvm::cantFail(TypeDeserializer::deserializeAs<PointerRecord>(cvt, pr));
+ return GetIntegralTypeInfo(pr.ReferentType, tpi);
+ }
+ case LF_ENUM: {
+ EnumRecord er;
+ llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));
+ return GetIntegralTypeInfo(er.UnderlyingType, tpi);
+ }
+ default:
+ assert(false && "Type is not integral!");
+ return {0, false};
+ }
+}
+
+template <typename StreamWriter>
+static DWARFExpression MakeLocationExpressionInternal(lldb::ModuleSP module,
+ StreamWriter &&writer) {
+ const ArchSpec &architecture = module->GetArchitecture();
+ ByteOrder byte_order = architecture.GetByteOrder();
+ uint32_t address_size = architecture.GetAddressByteSize();
+ uint32_t byte_size = architecture.GetDataByteSize();
+ if (byte_order == eByteOrderInvalid || address_size == 0)
+ return DWARFExpression();
+
+ RegisterKind register_kind = eRegisterKindDWARF;
+ StreamBuffer<32> stream(Stream::eBinary, address_size, byte_order);
+
+ if (!writer(stream, register_kind))
+ return DWARFExpression();
+
+ DataBufferSP buffer =
+ std::make_shared<DataBufferHeap>(stream.GetData(), stream.GetSize());
+ DataExtractor extractor(buffer, byte_order, address_size, byte_size);
+ DWARFExpression result(extractor);
+ result.SetRegisterKind(register_kind);
+
+ return result;
+}
+
+static bool MakeRegisterBasedLocationExpressionInternal(
+ Stream &stream, llvm::codeview::RegisterId reg, RegisterKind &register_kind,
+ std::optional<int32_t> relative_offset, lldb::ModuleSP module) {
+ uint32_t reg_num = GetRegisterNumber(module->GetArchitecture().GetMachine(),
+ reg, register_kind);
+ if (reg_num == LLDB_INVALID_REGNUM)
+ return false;
+
+ if (reg_num > 31) {
+ llvm::dwarf::LocationAtom base =
+ relative_offset ? llvm::dwarf::DW_OP_bregx : llvm::dwarf::DW_OP_regx;
+ stream.PutHex8(base);
+ stream.PutULEB128(reg_num);
+ } else {
+ llvm::dwarf::LocationAtom base =
+ relative_offset ? llvm::dwarf::DW_OP_breg0 : llvm::dwarf::DW_OP_reg0;
+ stream.PutHex8(base + reg_num);
+ }
+
+ if (relative_offset)
+ stream.PutSLEB128(*relative_offset);
+
+ return true;
+}
+
+static DWARFExpression MakeRegisterBasedLocationExpressionInternal(
+ llvm::codeview::RegisterId reg, std::optional<int32_t> relative_offset,
+ lldb::ModuleSP module) {
+ return MakeLocationExpressionInternal(
+ module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
+ return MakeRegisterBasedLocationExpressionInternal(
+ stream, reg, register_kind, relative_offset, module);
+ });
+}
+
+DWARFExpression lldb_private::npdb::MakeEnregisteredLocationExpression(
+ llvm::codeview::RegisterId reg, lldb::ModuleSP module) {
+ return MakeRegisterBasedLocationExpressionInternal(reg, std::nullopt, module);
+}
+
+DWARFExpression lldb_private::npdb::MakeRegRelLocationExpression(
+ llvm::codeview::RegisterId reg, int32_t offset, lldb::ModuleSP module) {
+ return MakeRegisterBasedLocationExpressionInternal(reg, offset, module);
+}
+
+static bool EmitVFrameEvaluationDWARFExpression(
+ llvm::StringRef program, llvm::Triple::ArchType arch_type, Stream &stream) {
+ // VFrame value always stored in $TO pseudo-register
+ return TranslateFPOProgramToDWARFExpression(program, "$T0", arch_type,
+ stream);
+}
+
+DWARFExpression lldb_private::npdb::MakeVFrameRelLocationExpression(
+ llvm::StringRef fpo_program, int32_t offset, lldb::ModuleSP module) {
+ return MakeLocationExpressionInternal(
+ module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
+ const ArchSpec &architecture = module->GetArchitecture();
+
+ if (!EmitVFrameEvaluationDWARFExpression(fpo_program, architecture.GetMachine(),
+ stream))
+ return false;
+
+ stream.PutHex8(llvm::dwarf::DW_OP_consts);
+ stream.PutSLEB128(offset);
+ stream.PutHex8(llvm::dwarf::DW_OP_plus);
+
+ register_kind = eRegisterKindLLDB;
+
+ return true;
+ });
+}
+
+DWARFExpression lldb_private::npdb::MakeGlobalLocationExpression(
+ uint16_t section, uint32_t offset, ModuleSP module) {
+ assert(section > 0);
+ assert(module);
+
+ return MakeLocationExpressionInternal(
+ module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
+ stream.PutHex8(llvm::dwarf::DW_OP_addr);
+
+ SectionList *section_list = module->GetSectionList();
+ assert(section_list);
+
+ auto section_ptr = section_list->FindSectionByID(section);
+ if (!section_ptr)
+ return false;
+
+ stream.PutMaxHex64(section_ptr->GetFileAddress() + offset,
+ stream.GetAddressByteSize(), stream.GetByteOrder());
+
+ return true;
+ });
+}
+
+DWARFExpression lldb_private::npdb::MakeConstantLocationExpression(
+ TypeIndex underlying_ti, TpiStream &tpi, const llvm::APSInt &constant,
+ ModuleSP module) {
+ const ArchSpec &architecture = module->GetArchitecture();
+ uint32_t address_size = architecture.GetAddressByteSize();
+
+ size_t size = 0;
+ bool is_signed = false;
+ std::tie(size, is_signed) = GetIntegralTypeInfo(underlying_ti, tpi);
+
+ union {
+ llvm::support::little64_t I;
+ llvm::support::ulittle64_t U;
+ } Value;
+
+ std::shared_ptr<DataBufferHeap> buffer = std::make_shared<DataBufferHeap>();
+ buffer->SetByteSize(size);
+
+ llvm::ArrayRef<uint8_t> bytes;
+ if (is_signed) {
+ Value.I = constant.getSExtValue();
+ } else {
+ Value.U = constant.getZExtValue();
+ }
+
+ bytes = llvm::ArrayRef(reinterpret_cast<const uint8_t *>(&Value), 8)
+ .take_front(size);
+ buffer->CopyData(bytes.data(), size);
+ DataExtractor extractor(buffer, lldb::eByteOrderLittle, address_size);
+ DWARFExpression result(extractor);
+ return result;
+}
+
+DWARFExpression
+lldb_private::npdb::MakeEnregisteredLocationExpressionForComposite(
+ const std::map<uint64_t, MemberValLocation> &offset_to_location,
+ std::map<uint64_t, size_t> &offset_to_size, size_t total_size,
+ lldb::ModuleSP module) {
+ return MakeLocationExpressionInternal(
+ module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
+ size_t cur_offset = 0;
+ bool is_simple_type = offset_to_size.empty();
+ // Iterate through offset_to_location because offset_to_size might be
+ // empty if the variable is a simple type.
+ for (const auto &offset_loc : offset_to_location) {
+ if (cur_offset < offset_loc.first) {
+ stream.PutHex8(llvm::dwarf::DW_OP_piece);
+ stream.PutULEB128(offset_loc.first - cur_offset);
+ cur_offset = offset_loc.first;
+ }
+ MemberValLocation loc = offset_loc.second;
+ std::optional<int32_t> offset =
+ loc.is_at_reg ? std::nullopt
+ : std::optional<int32_t>(loc.reg_offset);
+ if (!MakeRegisterBasedLocationExpressionInternal(
+ stream, (RegisterId)loc.reg_id, register_kind, offset,
+ module))
+ return false;
+ if (!is_simple_type) {
+ stream.PutHex8(llvm::dwarf::DW_OP_piece);
+ stream.PutULEB128(offset_to_size[offset_loc.first]);
+ cur_offset = offset_loc.first + offset_to_size[offset_loc.first];
+ }
+ }
+ // For simple type, it specifies the byte size of the value described by
+ // the previous dwarf expr. For udt, it's the remaining byte size at end
+ // of a struct.
+ if (total_size > cur_offset) {
+ stream.PutHex8(llvm::dwarf::DW_OP_piece);
+ stream.PutULEB128(total_size - cur_offset);
+ }
+ return true;
+ });
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h
new file mode 100644
index 000000000000..2f12d8bf0dd7
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h
@@ -0,0 +1,57 @@
+//===-- DWARFLocationExpression.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_NATIVEPDB_DWARFLOCATIONEXPRESSION_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_DWARFLOCATIONEXPRESSION_H
+
+#include "lldb/lldb-forward.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include <map>
+
+namespace llvm {
+class APSInt;
+class StringRef;
+namespace codeview {
+class TypeIndex;
+}
+namespace pdb {
+class TpiStream;
+}
+} // namespace llvm
+namespace lldb_private {
+namespace npdb {
+struct MemberValLocation {
+ uint16_t reg_id;
+ uint16_t reg_offset;
+ bool is_at_reg = true;
+};
+
+DWARFExpression
+MakeEnregisteredLocationExpression(llvm::codeview::RegisterId reg,
+ lldb::ModuleSP module);
+
+DWARFExpression MakeRegRelLocationExpression(llvm::codeview::RegisterId reg,
+ int32_t offset,
+ lldb::ModuleSP module);
+DWARFExpression MakeVFrameRelLocationExpression(llvm::StringRef fpo_program,
+ int32_t offset,
+ lldb::ModuleSP module);
+DWARFExpression MakeGlobalLocationExpression(uint16_t section, uint32_t offset,
+ lldb::ModuleSP module);
+DWARFExpression MakeConstantLocationExpression(
+ llvm::codeview::TypeIndex underlying_ti, llvm::pdb::TpiStream &tpi,
+ const llvm::APSInt &constant, lldb::ModuleSP module);
+DWARFExpression MakeEnregisteredLocationExpressionForComposite(
+ const std::map<uint64_t, MemberValLocation> &offset_to_location,
+ std::map<uint64_t, size_t> &offset_to_size, size_t total_size,
+ lldb::ModuleSP module);
+} // namespace npdb
+} // namespace lldb_private
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
new file mode 100644
index 000000000000..b79d3e63f72b
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
@@ -0,0 +1,1454 @@
+#include "PdbAstBuilder.h"
+
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/DebugInfo/CodeView/RecordName.h"
+#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecordHelpers.h"
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
+#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/Demangle/MicrosoftDemangle.h"
+
+#include "PdbUtil.h"
+#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h"
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
+#include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "SymbolFileNativePDB.h"
+#include "UdtRecordCompleter.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include <optional>
+#include <string_view>
+
+using namespace lldb_private;
+using namespace lldb_private::npdb;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+namespace {
+struct CreateMethodDecl : public TypeVisitorCallbacks {
+ CreateMethodDecl(PdbIndex &m_index, TypeSystemClang &m_clang,
+ TypeIndex func_type_index,
+ clang::FunctionDecl *&function_decl,
+ lldb::opaque_compiler_type_t parent_ty,
+ llvm::StringRef proc_name, CompilerType func_ct)
+ : m_index(m_index), m_clang(m_clang), func_type_index(func_type_index),
+ function_decl(function_decl), parent_ty(parent_ty),
+ proc_name(proc_name), func_ct(func_ct) {}
+ PdbIndex &m_index;
+ TypeSystemClang &m_clang;
+ TypeIndex func_type_index;
+ clang::FunctionDecl *&function_decl;
+ lldb::opaque_compiler_type_t parent_ty;
+ llvm::StringRef proc_name;
+ CompilerType func_ct;
+
+ llvm::Error visitKnownMember(CVMemberRecord &cvr,
+ OverloadedMethodRecord &overloaded) override {
+ TypeIndex method_list_idx = overloaded.MethodList;
+
+ CVType method_list_type = m_index.tpi().getType(method_list_idx);
+ assert(method_list_type.kind() == LF_METHODLIST);
+
+ MethodOverloadListRecord method_list;
+ llvm::cantFail(TypeDeserializer::deserializeAs<MethodOverloadListRecord>(
+ method_list_type, method_list));
+
+ for (const OneMethodRecord &method : method_list.Methods) {
+ if (method.getType().getIndex() == func_type_index.getIndex())
+ AddMethod(overloaded.Name, method.getAccess(), method.getOptions(),
+ method.Attrs);
+ }
+
+ return llvm::Error::success();
+ }
+
+ llvm::Error visitKnownMember(CVMemberRecord &cvr,
+ OneMethodRecord &record) override {
+ AddMethod(record.getName(), record.getAccess(), record.getOptions(),
+ record.Attrs);
+ return llvm::Error::success();
+ }
+
+ void AddMethod(llvm::StringRef name, MemberAccess access,
+ MethodOptions options, MemberAttributes attrs) {
+ if (name != proc_name || function_decl)
+ return;
+ lldb::AccessType access_type = TranslateMemberAccess(access);
+ bool is_virtual = attrs.isVirtual();
+ bool is_static = attrs.isStatic();
+ bool is_artificial = (options & MethodOptions::CompilerGenerated) ==
+ MethodOptions::CompilerGenerated;
+ function_decl = m_clang.AddMethodToCXXRecordType(
+ parent_ty, proc_name,
+ /*mangled_name=*/nullptr, func_ct, /*access=*/access_type,
+ /*is_virtual=*/is_virtual, /*is_static=*/is_static,
+ /*is_inline=*/false, /*is_explicit=*/false,
+ /*is_attr_used=*/false, /*is_artificial=*/is_artificial);
+ }
+};
+} // namespace
+
+static clang::TagTypeKind TranslateUdtKind(const TagRecord &cr) {
+ switch (cr.Kind) {
+ case TypeRecordKind::Class:
+ return clang::TagTypeKind::Class;
+ case TypeRecordKind::Struct:
+ return clang::TagTypeKind::Struct;
+ case TypeRecordKind::Union:
+ return clang::TagTypeKind::Union;
+ case TypeRecordKind::Interface:
+ return clang::TagTypeKind::Interface;
+ case TypeRecordKind::Enum:
+ return clang::TagTypeKind::Enum;
+ default:
+ lldbassert(false && "Invalid tag record kind!");
+ return clang::TagTypeKind::Struct;
+ }
+}
+
+static bool IsCVarArgsFunction(llvm::ArrayRef<TypeIndex> args) {
+ if (args.empty())
+ return false;
+ return args.back() == TypeIndex::None();
+}
+
+static bool
+AnyScopesHaveTemplateParams(llvm::ArrayRef<llvm::ms_demangle::Node *> scopes) {
+ for (llvm::ms_demangle::Node *n : scopes) {
+ auto *idn = static_cast<llvm::ms_demangle::IdentifierNode *>(n);
+ if (idn->TemplateParams)
+ return true;
+ }
+ return false;
+}
+
+static std::optional<clang::CallingConv>
+TranslateCallingConvention(llvm::codeview::CallingConvention conv) {
+ using CC = llvm::codeview::CallingConvention;
+ switch (conv) {
+
+ case CC::NearC:
+ case CC::FarC:
+ return clang::CallingConv::CC_C;
+ case CC::NearPascal:
+ case CC::FarPascal:
+ return clang::CallingConv::CC_X86Pascal;
+ case CC::NearFast:
+ case CC::FarFast:
+ return clang::CallingConv::CC_X86FastCall;
+ case CC::NearStdCall:
+ case CC::FarStdCall:
+ return clang::CallingConv::CC_X86StdCall;
+ case CC::ThisCall:
+ return clang::CallingConv::CC_X86ThisCall;
+ case CC::NearVector:
+ return clang::CallingConv::CC_X86VectorCall;
+ default:
+ return std::nullopt;
+ }
+}
+
+static bool IsAnonymousNamespaceName(llvm::StringRef name) {
+ return name == "`anonymous namespace'" || name == "`anonymous-namespace'";
+}
+
+PdbAstBuilder::PdbAstBuilder(TypeSystemClang &clang) : m_clang(clang) {}
+
+lldb_private::CompilerDeclContext PdbAstBuilder::GetTranslationUnitDecl() {
+ return ToCompilerDeclContext(*m_clang.GetTranslationUnitDecl());
+}
+
+std::pair<clang::DeclContext *, std::string>
+PdbAstBuilder::CreateDeclInfoForType(const TagRecord &record, TypeIndex ti) {
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ // FIXME: Move this to GetDeclContextContainingUID.
+ if (!record.hasUniqueName())
+ return CreateDeclInfoForUndecoratedName(record.Name);
+
+ llvm::ms_demangle::Demangler demangler;
+ std::string_view sv(record.UniqueName.begin(), record.UniqueName.size());
+ llvm::ms_demangle::TagTypeNode *ttn = demangler.parseTagUniqueName(sv);
+ if (demangler.Error)
+ return {m_clang.GetTranslationUnitDecl(), std::string(record.UniqueName)};
+
+ llvm::ms_demangle::IdentifierNode *idn =
+ ttn->QualifiedName->getUnqualifiedIdentifier();
+ std::string uname = idn->toString(llvm::ms_demangle::OF_NoTagSpecifier);
+
+ llvm::ms_demangle::NodeArrayNode *name_components =
+ ttn->QualifiedName->Components;
+ llvm::ArrayRef<llvm::ms_demangle::Node *> scopes(name_components->Nodes,
+ name_components->Count - 1);
+
+ clang::DeclContext *context = m_clang.GetTranslationUnitDecl();
+
+ // If this type doesn't have a parent type in the debug info, then the best we
+ // can do is to say that it's either a series of namespaces (if the scope is
+ // non-empty), or the translation unit (if the scope is empty).
+ std::optional<TypeIndex> parent_index = pdb->GetParentType(ti);
+ if (!parent_index) {
+ if (scopes.empty())
+ return {context, uname};
+
+ // If there is no parent in the debug info, but some of the scopes have
+ // template params, then this is a case of bad debug info. See, for
+ // example, llvm.org/pr39607. We don't want to create an ambiguity between
+ // a NamespaceDecl and a CXXRecordDecl, so instead we create a class at
+ // global scope with the fully qualified name.
+ if (AnyScopesHaveTemplateParams(scopes))
+ return {context, std::string(record.Name)};
+
+ for (llvm::ms_demangle::Node *scope : scopes) {
+ auto *nii = static_cast<llvm::ms_demangle::NamedIdentifierNode *>(scope);
+ std::string str = nii->toString();
+ context = GetOrCreateNamespaceDecl(str.c_str(), *context);
+ }
+ return {context, uname};
+ }
+
+ // Otherwise, all we need to do is get the parent type of this type and
+ // recurse into our lazy type creation / AST reconstruction logic to get an
+ // LLDB TypeSP for the parent. This will cause the AST to automatically get
+ // the right DeclContext created for any parent.
+ clang::QualType parent_qt = GetOrCreateType(*parent_index);
+ if (parent_qt.isNull())
+ return {nullptr, ""};
+
+ context = clang::TagDecl::castToDeclContext(parent_qt->getAsTagDecl());
+ return {context, uname};
+}
+
+static bool isLocalVariableType(SymbolKind K) {
+ switch (K) {
+ case S_REGISTER:
+ case S_REGREL32:
+ case S_LOCAL:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+clang::Decl *PdbAstBuilder::GetOrCreateSymbolForId(PdbCompilandSymId id) {
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ CVSymbol cvs = index.ReadSymbolRecord(id);
+
+ if (isLocalVariableType(cvs.kind())) {
+ clang::DeclContext *scope = GetParentDeclContext(id);
+ if (!scope)
+ return nullptr;
+ clang::Decl *scope_decl = clang::Decl::castFromDeclContext(scope);
+ PdbCompilandSymId scope_id =
+ PdbSymUid(m_decl_to_status[scope_decl].uid).asCompilandSym();
+ return GetOrCreateVariableDecl(scope_id, id);
+ }
+
+ switch (cvs.kind()) {
+ case S_GPROC32:
+ case S_LPROC32:
+ return GetOrCreateFunctionDecl(id);
+ case S_GDATA32:
+ case S_LDATA32:
+ case S_GTHREAD32:
+ case S_CONSTANT:
+ // global variable
+ return nullptr;
+ case S_BLOCK32:
+ return GetOrCreateBlockDecl(id);
+ case S_INLINESITE:
+ return GetOrCreateInlinedFunctionDecl(id);
+ default:
+ return nullptr;
+ }
+}
+
+std::optional<CompilerDecl>
+PdbAstBuilder::GetOrCreateDeclForUid(PdbSymUid uid) {
+ if (clang::Decl *result = TryGetDecl(uid))
+ return ToCompilerDecl(*result);
+
+ clang::Decl *result = nullptr;
+ switch (uid.kind()) {
+ case PdbSymUidKind::CompilandSym:
+ result = GetOrCreateSymbolForId(uid.asCompilandSym());
+ break;
+ case PdbSymUidKind::Type: {
+ clang::QualType qt = GetOrCreateType(uid.asTypeSym());
+ if (qt.isNull())
+ return std::nullopt;
+ if (auto *tag = qt->getAsTagDecl()) {
+ result = tag;
+ break;
+ }
+ return std::nullopt;
+ }
+ default:
+ return std::nullopt;
+ }
+
+ if (!result)
+ return std::nullopt;
+ m_uid_to_decl[toOpaqueUid(uid)] = result;
+ return ToCompilerDecl(*result);
+}
+
+clang::DeclContext *PdbAstBuilder::GetOrCreateDeclContextForUid(PdbSymUid uid) {
+ if (uid.kind() == PdbSymUidKind::CompilandSym) {
+ if (uid.asCompilandSym().offset == 0)
+ return FromCompilerDeclContext(GetTranslationUnitDecl());
+ }
+ auto option = GetOrCreateDeclForUid(uid);
+ if (!option)
+ return nullptr;
+ clang::Decl *decl = FromCompilerDecl(*option);
+ if (!decl)
+ return nullptr;
+
+ return clang::Decl::castToDeclContext(decl);
+}
+
+std::pair<clang::DeclContext *, std::string>
+PdbAstBuilder::CreateDeclInfoForUndecoratedName(llvm::StringRef name) {
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ MSVCUndecoratedNameParser parser(name);
+ llvm::ArrayRef<MSVCUndecoratedNameSpecifier> specs = parser.GetSpecifiers();
+
+ auto *context = FromCompilerDeclContext(GetTranslationUnitDecl());
+
+ llvm::StringRef uname = specs.back().GetBaseName();
+ specs = specs.drop_back();
+ if (specs.empty())
+ return {context, std::string(name)};
+
+ llvm::StringRef scope_name = specs.back().GetFullName();
+
+ // It might be a class name, try that first.
+ std::vector<TypeIndex> types = index.tpi().findRecordsByName(scope_name);
+ while (!types.empty()) {
+ clang::QualType qt = GetOrCreateType(types.back());
+ if (qt.isNull())
+ continue;
+ clang::TagDecl *tag = qt->getAsTagDecl();
+ if (tag)
+ return {clang::TagDecl::castToDeclContext(tag), std::string(uname)};
+ types.pop_back();
+ }
+
+ // If that fails, treat it as a series of namespaces.
+ for (const MSVCUndecoratedNameSpecifier &spec : specs) {
+ std::string ns_name = spec.GetBaseName().str();
+ context = GetOrCreateNamespaceDecl(ns_name.c_str(), *context);
+ }
+ return {context, std::string(uname)};
+}
+
+clang::DeclContext *PdbAstBuilder::GetParentDeclContext(PdbSymUid uid) {
+ // We must do this *without* calling GetOrCreate on the current uid, as
+ // that would be an infinite recursion.
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex& index = pdb->GetIndex();
+ switch (uid.kind()) {
+ case PdbSymUidKind::CompilandSym: {
+ std::optional<PdbCompilandSymId> scope =
+ pdb->FindSymbolScope(uid.asCompilandSym());
+ if (scope)
+ return GetOrCreateDeclContextForUid(*scope);
+
+ CVSymbol sym = index.ReadSymbolRecord(uid.asCompilandSym());
+ return CreateDeclInfoForUndecoratedName(getSymbolName(sym)).first;
+ }
+ case PdbSymUidKind::Type: {
+ // It could be a namespace, class, or global. We don't support nested
+ // functions yet. Anyway, we just need to consult the parent type map.
+ PdbTypeSymId type_id = uid.asTypeSym();
+ std::optional<TypeIndex> parent_index = pdb->GetParentType(type_id.index);
+ if (!parent_index)
+ return FromCompilerDeclContext(GetTranslationUnitDecl());
+ return GetOrCreateDeclContextForUid(PdbTypeSymId(*parent_index));
+ }
+ case PdbSymUidKind::FieldListMember:
+ // In this case the parent DeclContext is the one for the class that this
+ // member is inside of.
+ break;
+ case PdbSymUidKind::GlobalSym: {
+ // If this refers to a compiland symbol, just recurse in with that symbol.
+ // The only other possibilities are S_CONSTANT and S_UDT, in which case we
+ // need to parse the undecorated name to figure out the scope, then look
+ // that up in the TPI stream. If it's found, it's a type, othewrise it's
+ // a series of namespaces.
+ // FIXME: do this.
+ CVSymbol global = index.ReadSymbolRecord(uid.asGlobalSym());
+ switch (global.kind()) {
+ case SymbolKind::S_GDATA32:
+ case SymbolKind::S_LDATA32:
+ return CreateDeclInfoForUndecoratedName(getSymbolName(global)).first;;
+ case SymbolKind::S_PROCREF:
+ case SymbolKind::S_LPROCREF: {
+ ProcRefSym ref{global.kind()};
+ llvm::cantFail(
+ SymbolDeserializer::deserializeAs<ProcRefSym>(global, ref));
+ PdbCompilandSymId cu_sym_id{ref.modi(), ref.SymOffset};
+ return GetParentDeclContext(cu_sym_id);
+ }
+ case SymbolKind::S_CONSTANT:
+ case SymbolKind::S_UDT:
+ return CreateDeclInfoForUndecoratedName(getSymbolName(global)).first;
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return FromCompilerDeclContext(GetTranslationUnitDecl());
+}
+
+bool PdbAstBuilder::CompleteType(clang::QualType qt) {
+ if (qt.isNull())
+ return false;
+ clang::TagDecl *tag = qt->getAsTagDecl();
+ if (qt->isArrayType()) {
+ const clang::Type *element_type = qt->getArrayElementTypeNoTypeQual();
+ tag = element_type->getAsTagDecl();
+ }
+ if (!tag)
+ return false;
+
+ return CompleteTagDecl(*tag);
+}
+
+bool PdbAstBuilder::CompleteTagDecl(clang::TagDecl &tag) {
+ // If this is not in our map, it's an error.
+ auto status_iter = m_decl_to_status.find(&tag);
+ lldbassert(status_iter != m_decl_to_status.end());
+
+ // If it's already complete, just return.
+ DeclStatus &status = status_iter->second;
+ if (status.resolved)
+ return true;
+
+ PdbTypeSymId type_id = PdbSymUid(status.uid).asTypeSym();
+ PdbIndex &index = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile())
+ ->GetIndex();
+ lldbassert(IsTagRecord(type_id, index.tpi()));
+
+ clang::QualType tag_qt = m_clang.getASTContext().getTypeDeclType(&tag);
+ TypeSystemClang::SetHasExternalStorage(tag_qt.getAsOpaquePtr(), false);
+
+ TypeIndex tag_ti = type_id.index;
+ CVType cvt = index.tpi().getType(tag_ti);
+ if (cvt.kind() == LF_MODIFIER)
+ tag_ti = LookThroughModifierRecord(cvt);
+
+ PdbTypeSymId best_ti = GetBestPossibleDecl(tag_ti, index.tpi());
+ cvt = index.tpi().getType(best_ti.index);
+ lldbassert(IsTagRecord(cvt));
+
+ if (IsForwardRefUdt(cvt)) {
+ // If we can't find a full decl for this forward ref anywhere in the debug
+ // info, then we have no way to complete it.
+ return false;
+ }
+
+ TypeIndex field_list_ti = GetFieldListIndex(cvt);
+ CVType field_list_cvt = index.tpi().getType(field_list_ti);
+ if (field_list_cvt.kind() != LF_FIELDLIST)
+ return false;
+ FieldListRecord field_list;
+ if (llvm::Error error = TypeDeserializer::deserializeAs<FieldListRecord>(
+ field_list_cvt, field_list))
+ llvm::consumeError(std::move(error));
+
+ // Visit all members of this class, then perform any finalization necessary
+ // to complete the class.
+ CompilerType ct = ToCompilerType(tag_qt);
+ UdtRecordCompleter completer(best_ti, ct, tag, *this, index, m_decl_to_status,
+ m_cxx_record_map);
+ llvm::Error error =
+ llvm::codeview::visitMemberRecordStream(field_list.Data, completer);
+ completer.complete();
+
+ m_decl_to_status[&tag].resolved = true;
+ if (error) {
+ llvm::consumeError(std::move(error));
+ return false;
+ }
+ return true;
+}
+
+clang::QualType PdbAstBuilder::CreateSimpleType(TypeIndex ti) {
+ if (ti == TypeIndex::NullptrT())
+ return GetBasicType(lldb::eBasicTypeNullPtr);
+
+ if (ti.getSimpleMode() != SimpleTypeMode::Direct) {
+ clang::QualType direct_type = GetOrCreateType(ti.makeDirect());
+ if (direct_type.isNull())
+ return {};
+ return m_clang.getASTContext().getPointerType(direct_type);
+ }
+
+ if (ti.getSimpleKind() == SimpleTypeKind::NotTranslated)
+ return {};
+
+ lldb::BasicType bt = GetCompilerTypeForSimpleKind(ti.getSimpleKind());
+ if (bt == lldb::eBasicTypeInvalid)
+ return {};
+
+ return GetBasicType(bt);
+}
+
+clang::QualType PdbAstBuilder::CreatePointerType(const PointerRecord &pointer) {
+ clang::QualType pointee_type = GetOrCreateType(pointer.ReferentType);
+
+ // This can happen for pointers to LF_VTSHAPE records, which we shouldn't
+ // create in the AST.
+ if (pointee_type.isNull())
+ return {};
+
+ if (pointer.isPointerToMember()) {
+ MemberPointerInfo mpi = pointer.getMemberInfo();
+ clang::QualType class_type = GetOrCreateType(mpi.ContainingType);
+ if (class_type.isNull())
+ return {};
+ if (clang::TagDecl *tag = class_type->getAsTagDecl()) {
+ clang::MSInheritanceAttr::Spelling spelling;
+ switch (mpi.Representation) {
+ case llvm::codeview::PointerToMemberRepresentation::SingleInheritanceData:
+ case llvm::codeview::PointerToMemberRepresentation::
+ SingleInheritanceFunction:
+ spelling =
+ clang::MSInheritanceAttr::Spelling::Keyword_single_inheritance;
+ break;
+ case llvm::codeview::PointerToMemberRepresentation::
+ MultipleInheritanceData:
+ case llvm::codeview::PointerToMemberRepresentation::
+ MultipleInheritanceFunction:
+ spelling =
+ clang::MSInheritanceAttr::Spelling::Keyword_multiple_inheritance;
+ break;
+ case llvm::codeview::PointerToMemberRepresentation::
+ VirtualInheritanceData:
+ case llvm::codeview::PointerToMemberRepresentation::
+ VirtualInheritanceFunction:
+ spelling =
+ clang::MSInheritanceAttr::Spelling::Keyword_virtual_inheritance;
+ break;
+ case llvm::codeview::PointerToMemberRepresentation::Unknown:
+ spelling =
+ clang::MSInheritanceAttr::Spelling::Keyword_unspecified_inheritance;
+ break;
+ default:
+ spelling = clang::MSInheritanceAttr::Spelling::SpellingNotCalculated;
+ break;
+ }
+ tag->addAttr(clang::MSInheritanceAttr::CreateImplicit(
+ m_clang.getASTContext(), spelling));
+ }
+ return m_clang.getASTContext().getMemberPointerType(
+ pointee_type, class_type.getTypePtr());
+ }
+
+ clang::QualType pointer_type;
+ if (pointer.getMode() == PointerMode::LValueReference)
+ pointer_type = m_clang.getASTContext().getLValueReferenceType(pointee_type);
+ else if (pointer.getMode() == PointerMode::RValueReference)
+ pointer_type = m_clang.getASTContext().getRValueReferenceType(pointee_type);
+ else
+ pointer_type = m_clang.getASTContext().getPointerType(pointee_type);
+
+ if ((pointer.getOptions() & PointerOptions::Const) != PointerOptions::None)
+ pointer_type.addConst();
+
+ if ((pointer.getOptions() & PointerOptions::Volatile) != PointerOptions::None)
+ pointer_type.addVolatile();
+
+ if ((pointer.getOptions() & PointerOptions::Restrict) != PointerOptions::None)
+ pointer_type.addRestrict();
+
+ return pointer_type;
+}
+
+clang::QualType
+PdbAstBuilder::CreateModifierType(const ModifierRecord &modifier) {
+ clang::QualType unmodified_type = GetOrCreateType(modifier.ModifiedType);
+ if (unmodified_type.isNull())
+ return {};
+
+ if ((modifier.Modifiers & ModifierOptions::Const) != ModifierOptions::None)
+ unmodified_type.addConst();
+ if ((modifier.Modifiers & ModifierOptions::Volatile) != ModifierOptions::None)
+ unmodified_type.addVolatile();
+
+ return unmodified_type;
+}
+
+clang::QualType PdbAstBuilder::CreateRecordType(PdbTypeSymId id,
+ const TagRecord &record) {
+ clang::DeclContext *context = nullptr;
+ std::string uname;
+ std::tie(context, uname) = CreateDeclInfoForType(record, id.index);
+ if (!context)
+ return {};
+
+ clang::TagTypeKind ttk = TranslateUdtKind(record);
+ lldb::AccessType access = (ttk == clang::TagTypeKind::Class)
+ ? lldb::eAccessPrivate
+ : lldb::eAccessPublic;
+
+ ClangASTMetadata metadata;
+ metadata.SetUserID(toOpaqueUid(id));
+ metadata.SetIsDynamicCXXType(false);
+
+ CompilerType ct = m_clang.CreateRecordType(
+ context, OptionalClangModuleID(), access, uname, llvm::to_underlying(ttk),
+ lldb::eLanguageTypeC_plus_plus, &metadata);
+
+ lldbassert(ct.IsValid());
+
+ TypeSystemClang::StartTagDeclarationDefinition(ct);
+
+ // Even if it's possible, don't complete it at this point. Just mark it
+ // forward resolved, and if/when LLDB needs the full definition, it can
+ // ask us.
+ clang::QualType result =
+ clang::QualType::getFromOpaquePtr(ct.GetOpaqueQualType());
+
+ TypeSystemClang::SetHasExternalStorage(result.getAsOpaquePtr(), true);
+ return result;
+}
+
+clang::Decl *PdbAstBuilder::TryGetDecl(PdbSymUid uid) const {
+ auto iter = m_uid_to_decl.find(toOpaqueUid(uid));
+ if (iter != m_uid_to_decl.end())
+ return iter->second;
+ return nullptr;
+}
+
+clang::NamespaceDecl *
+PdbAstBuilder::GetOrCreateNamespaceDecl(const char *name,
+ clang::DeclContext &context) {
+ return m_clang.GetUniqueNamespaceDeclaration(
+ IsAnonymousNamespaceName(name) ? nullptr : name, &context,
+ OptionalClangModuleID());
+}
+
+clang::BlockDecl *
+PdbAstBuilder::GetOrCreateBlockDecl(PdbCompilandSymId block_id) {
+ if (clang::Decl *decl = TryGetDecl(block_id))
+ return llvm::dyn_cast<clang::BlockDecl>(decl);
+
+ clang::DeclContext *scope = GetParentDeclContext(block_id);
+
+ clang::BlockDecl *block_decl =
+ m_clang.CreateBlockDeclaration(scope, OptionalClangModuleID());
+ m_uid_to_decl.insert({toOpaqueUid(block_id), block_decl});
+
+ DeclStatus status;
+ status.resolved = true;
+ status.uid = toOpaqueUid(block_id);
+ m_decl_to_status.insert({block_decl, status});
+
+ return block_decl;
+}
+
+clang::VarDecl *PdbAstBuilder::CreateVariableDecl(PdbSymUid uid, CVSymbol sym,
+ clang::DeclContext &scope) {
+ VariableInfo var_info = GetVariableNameInfo(sym);
+ clang::QualType qt = GetOrCreateType(var_info.type);
+ if (qt.isNull())
+ return nullptr;
+
+ clang::VarDecl *var_decl = m_clang.CreateVariableDeclaration(
+ &scope, OptionalClangModuleID(), var_info.name.str().c_str(), qt);
+
+ m_uid_to_decl[toOpaqueUid(uid)] = var_decl;
+ DeclStatus status;
+ status.resolved = true;
+ status.uid = toOpaqueUid(uid);
+ m_decl_to_status.insert({var_decl, status});
+ return var_decl;
+}
+
+clang::VarDecl *
+PdbAstBuilder::GetOrCreateVariableDecl(PdbCompilandSymId scope_id,
+ PdbCompilandSymId var_id) {
+ if (clang::Decl *decl = TryGetDecl(var_id))
+ return llvm::dyn_cast<clang::VarDecl>(decl);
+
+ clang::DeclContext *scope = GetOrCreateDeclContextForUid(scope_id);
+ if (!scope)
+ return nullptr;
+
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ CVSymbol sym = index.ReadSymbolRecord(var_id);
+ return CreateVariableDecl(PdbSymUid(var_id), sym, *scope);
+}
+
+clang::VarDecl *PdbAstBuilder::GetOrCreateVariableDecl(PdbGlobalSymId var_id) {
+ if (clang::Decl *decl = TryGetDecl(var_id))
+ return llvm::dyn_cast<clang::VarDecl>(decl);
+
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ CVSymbol sym = index.ReadSymbolRecord(var_id);
+ auto context = FromCompilerDeclContext(GetTranslationUnitDecl());
+ return CreateVariableDecl(PdbSymUid(var_id), sym, *context);
+}
+
+clang::TypedefNameDecl *
+PdbAstBuilder::GetOrCreateTypedefDecl(PdbGlobalSymId id) {
+ if (clang::Decl *decl = TryGetDecl(id))
+ return llvm::dyn_cast<clang::TypedefNameDecl>(decl);
+
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ CVSymbol sym = index.ReadSymbolRecord(id);
+ lldbassert(sym.kind() == S_UDT);
+ UDTSym udt = llvm::cantFail(SymbolDeserializer::deserializeAs<UDTSym>(sym));
+
+ clang::DeclContext *scope = GetParentDeclContext(id);
+
+ PdbTypeSymId real_type_id{udt.Type, false};
+ clang::QualType qt = GetOrCreateType(real_type_id);
+ if (qt.isNull() || !scope)
+ return nullptr;
+
+ std::string uname = std::string(DropNameScope(udt.Name));
+
+ CompilerType ct = ToCompilerType(qt).CreateTypedef(
+ uname.c_str(), ToCompilerDeclContext(*scope), 0);
+ clang::TypedefNameDecl *tnd = m_clang.GetAsTypedefDecl(ct);
+ DeclStatus status;
+ status.resolved = true;
+ status.uid = toOpaqueUid(id);
+ m_decl_to_status.insert({tnd, status});
+ return tnd;
+}
+
+clang::QualType PdbAstBuilder::GetBasicType(lldb::BasicType type) {
+ CompilerType ct = m_clang.GetBasicType(type);
+ return clang::QualType::getFromOpaquePtr(ct.GetOpaqueQualType());
+}
+
+clang::QualType PdbAstBuilder::CreateType(PdbTypeSymId type) {
+ if (type.index.isSimple())
+ return CreateSimpleType(type.index);
+
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ CVType cvt = index.tpi().getType(type.index);
+
+ if (cvt.kind() == LF_MODIFIER) {
+ ModifierRecord modifier;
+ llvm::cantFail(
+ TypeDeserializer::deserializeAs<ModifierRecord>(cvt, modifier));
+ return CreateModifierType(modifier);
+ }
+
+ if (cvt.kind() == LF_POINTER) {
+ PointerRecord pointer;
+ llvm::cantFail(
+ TypeDeserializer::deserializeAs<PointerRecord>(cvt, pointer));
+ return CreatePointerType(pointer);
+ }
+
+ if (IsTagRecord(cvt)) {
+ CVTagRecord tag = CVTagRecord::create(cvt);
+ if (tag.kind() == CVTagRecord::Union)
+ return CreateRecordType(type.index, tag.asUnion());
+ if (tag.kind() == CVTagRecord::Enum)
+ return CreateEnumType(type.index, tag.asEnum());
+ return CreateRecordType(type.index, tag.asClass());
+ }
+
+ if (cvt.kind() == LF_ARRAY) {
+ ArrayRecord ar;
+ llvm::cantFail(TypeDeserializer::deserializeAs<ArrayRecord>(cvt, ar));
+ return CreateArrayType(ar);
+ }
+
+ if (cvt.kind() == LF_PROCEDURE) {
+ ProcedureRecord pr;
+ llvm::cantFail(TypeDeserializer::deserializeAs<ProcedureRecord>(cvt, pr));
+ return CreateFunctionType(pr.ArgumentList, pr.ReturnType, pr.CallConv);
+ }
+
+ if (cvt.kind() == LF_MFUNCTION) {
+ MemberFunctionRecord mfr;
+ llvm::cantFail(
+ TypeDeserializer::deserializeAs<MemberFunctionRecord>(cvt, mfr));
+ return CreateFunctionType(mfr.ArgumentList, mfr.ReturnType, mfr.CallConv);
+ }
+
+ return {};
+}
+
+clang::QualType PdbAstBuilder::GetOrCreateType(PdbTypeSymId type) {
+ if (type.index.isNoneType())
+ return {};
+
+ lldb::user_id_t uid = toOpaqueUid(type);
+ auto iter = m_uid_to_type.find(uid);
+ if (iter != m_uid_to_type.end())
+ return iter->second;
+
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ PdbTypeSymId best_type = GetBestPossibleDecl(type, index.tpi());
+
+ clang::QualType qt;
+ if (best_type.index != type.index) {
+ // This is a forward decl. Call GetOrCreate on the full decl, then map the
+ // forward decl id to the full decl QualType.
+ clang::QualType qt = GetOrCreateType(best_type);
+ if (qt.isNull())
+ return {};
+ m_uid_to_type[toOpaqueUid(type)] = qt;
+ return qt;
+ }
+
+ // This is either a full decl, or a forward decl with no matching full decl
+ // in the debug info.
+ qt = CreateType(type);
+ if (qt.isNull())
+ return {};
+
+ m_uid_to_type[toOpaqueUid(type)] = qt;
+ if (IsTagRecord(type, index.tpi())) {
+ clang::TagDecl *tag = qt->getAsTagDecl();
+ lldbassert(m_decl_to_status.count(tag) == 0);
+
+ DeclStatus &status = m_decl_to_status[tag];
+ status.uid = uid;
+ status.resolved = false;
+ }
+ return qt;
+}
+
+clang::FunctionDecl *
+PdbAstBuilder::CreateFunctionDecl(PdbCompilandSymId func_id,
+ llvm::StringRef func_name, TypeIndex func_ti,
+ CompilerType func_ct, uint32_t param_count,
+ clang::StorageClass func_storage,
+ bool is_inline, clang::DeclContext *parent) {
+ clang::FunctionDecl *function_decl = nullptr;
+ if (parent->isRecord()) {
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ clang::QualType parent_qt = llvm::cast<clang::TypeDecl>(parent)
+ ->getTypeForDecl()
+ ->getCanonicalTypeInternal();
+ lldb::opaque_compiler_type_t parent_opaque_ty =
+ ToCompilerType(parent_qt).GetOpaqueQualType();
+ // FIXME: Remove this workaround.
+ auto iter = m_cxx_record_map.find(parent_opaque_ty);
+ if (iter != m_cxx_record_map.end()) {
+ if (iter->getSecond().contains({func_name, func_ct})) {
+ return nullptr;
+ }
+ }
+
+ CVType cvt = index.tpi().getType(func_ti);
+ MemberFunctionRecord func_record(static_cast<TypeRecordKind>(cvt.kind()));
+ llvm::cantFail(TypeDeserializer::deserializeAs<MemberFunctionRecord>(
+ cvt, func_record));
+ TypeIndex class_index = func_record.getClassType();
+
+ CVType parent_cvt = index.tpi().getType(class_index);
+ TagRecord tag_record = CVTagRecord::create(parent_cvt).asTag();
+ // If it's a forward reference, try to get the real TypeIndex.
+ if (tag_record.isForwardRef()) {
+ llvm::Expected<TypeIndex> eti =
+ index.tpi().findFullDeclForForwardRef(class_index);
+ if (eti) {
+ tag_record = CVTagRecord::create(index.tpi().getType(*eti)).asTag();
+ }
+ }
+ if (!tag_record.FieldList.isSimple()) {
+ CVType field_list_cvt = index.tpi().getType(tag_record.FieldList);
+ FieldListRecord field_list;
+ if (llvm::Error error = TypeDeserializer::deserializeAs<FieldListRecord>(
+ field_list_cvt, field_list))
+ llvm::consumeError(std::move(error));
+ CreateMethodDecl process(index, m_clang, func_ti, function_decl,
+ parent_opaque_ty, func_name, func_ct);
+ if (llvm::Error err = visitMemberRecordStream(field_list.Data, process))
+ llvm::consumeError(std::move(err));
+ }
+
+ if (!function_decl) {
+ function_decl = m_clang.AddMethodToCXXRecordType(
+ parent_opaque_ty, func_name,
+ /*mangled_name=*/nullptr, func_ct,
+ /*access=*/lldb::AccessType::eAccessPublic,
+ /*is_virtual=*/false, /*is_static=*/false,
+ /*is_inline=*/false, /*is_explicit=*/false,
+ /*is_attr_used=*/false, /*is_artificial=*/false);
+ }
+ m_cxx_record_map[parent_opaque_ty].insert({func_name, func_ct});
+ } else {
+ function_decl = m_clang.CreateFunctionDeclaration(
+ parent, OptionalClangModuleID(), func_name, func_ct, func_storage,
+ is_inline);
+ CreateFunctionParameters(func_id, *function_decl, param_count);
+ }
+ return function_decl;
+}
+
+clang::FunctionDecl *
+PdbAstBuilder::GetOrCreateInlinedFunctionDecl(PdbCompilandSymId inlinesite_id) {
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ CompilandIndexItem *cii =
+ index.compilands().GetCompiland(inlinesite_id.modi);
+ CVSymbol sym = cii->m_debug_stream.readSymbolAtOffset(inlinesite_id.offset);
+ InlineSiteSym inline_site(static_cast<SymbolRecordKind>(sym.kind()));
+ cantFail(SymbolDeserializer::deserializeAs<InlineSiteSym>(sym, inline_site));
+
+ // Inlinee is the id index to the function id record that is inlined.
+ PdbTypeSymId func_id(inline_site.Inlinee, true);
+ // Look up the function decl by the id index to see if we have created a
+ // function decl for a different inlinesite that refers the same function.
+ if (clang::Decl *decl = TryGetDecl(func_id))
+ return llvm::dyn_cast<clang::FunctionDecl>(decl);
+ clang::FunctionDecl *function_decl =
+ CreateFunctionDeclFromId(func_id, inlinesite_id);
+ if (function_decl == nullptr)
+ return nullptr;
+
+ // Use inline site id in m_decl_to_status because it's expected to be a
+ // PdbCompilandSymId so that we can parse local variables info after it.
+ uint64_t inlinesite_uid = toOpaqueUid(inlinesite_id);
+ DeclStatus status;
+ status.resolved = true;
+ status.uid = inlinesite_uid;
+ m_decl_to_status.insert({function_decl, status});
+ // Use the index in IPI stream as uid in m_uid_to_decl, because index in IPI
+ // stream are unique and there could be multiple inline sites (different ids)
+ // referring the same inline function. This avoid creating multiple same
+ // inline function delcs.
+ uint64_t func_uid = toOpaqueUid(func_id);
+ lldbassert(m_uid_to_decl.count(func_uid) == 0);
+ m_uid_to_decl[func_uid] = function_decl;
+ return function_decl;
+}
+
+clang::FunctionDecl *
+PdbAstBuilder::CreateFunctionDeclFromId(PdbTypeSymId func_tid,
+ PdbCompilandSymId func_sid) {
+ lldbassert(func_tid.is_ipi);
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ CVType func_cvt = index.ipi().getType(func_tid.index);
+ llvm::StringRef func_name;
+ TypeIndex func_ti;
+ clang::DeclContext *parent = nullptr;
+ switch (func_cvt.kind()) {
+ case LF_MFUNC_ID: {
+ MemberFuncIdRecord mfr;
+ cantFail(
+ TypeDeserializer::deserializeAs<MemberFuncIdRecord>(func_cvt, mfr));
+ func_name = mfr.getName();
+ func_ti = mfr.getFunctionType();
+ PdbTypeSymId class_type_id(mfr.ClassType, false);
+ parent = GetOrCreateDeclContextForUid(class_type_id);
+ break;
+ }
+ case LF_FUNC_ID: {
+ FuncIdRecord fir;
+ cantFail(TypeDeserializer::deserializeAs<FuncIdRecord>(func_cvt, fir));
+ func_name = fir.getName();
+ func_ti = fir.getFunctionType();
+ parent = FromCompilerDeclContext(GetTranslationUnitDecl());
+ if (!fir.ParentScope.isNoneType()) {
+ CVType parent_cvt = index.ipi().getType(fir.ParentScope);
+ if (parent_cvt.kind() == LF_STRING_ID) {
+ StringIdRecord sir;
+ cantFail(
+ TypeDeserializer::deserializeAs<StringIdRecord>(parent_cvt, sir));
+ parent = GetOrCreateNamespaceDecl(sir.String.data(), *parent);
+ }
+ }
+ break;
+ }
+ default:
+ lldbassert(false && "Invalid function id type!");
+ }
+ clang::QualType func_qt = GetOrCreateType(func_ti);
+ if (func_qt.isNull() || !parent)
+ return nullptr;
+ CompilerType func_ct = ToCompilerType(func_qt);
+ uint32_t param_count =
+ llvm::cast<clang::FunctionProtoType>(func_qt)->getNumParams();
+ return CreateFunctionDecl(func_sid, func_name, func_ti, func_ct, param_count,
+ clang::SC_None, true, parent);
+}
+
+clang::FunctionDecl *
+PdbAstBuilder::GetOrCreateFunctionDecl(PdbCompilandSymId func_id) {
+ if (clang::Decl *decl = TryGetDecl(func_id))
+ return llvm::dyn_cast<clang::FunctionDecl>(decl);
+
+ clang::DeclContext *parent = GetParentDeclContext(PdbSymUid(func_id));
+ if (!parent)
+ return nullptr;
+ std::string context_name;
+ if (clang::NamespaceDecl *ns = llvm::dyn_cast<clang::NamespaceDecl>(parent)) {
+ context_name = ns->getQualifiedNameAsString();
+ } else if (clang::TagDecl *tag = llvm::dyn_cast<clang::TagDecl>(parent)) {
+ context_name = tag->getQualifiedNameAsString();
+ }
+
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ CVSymbol cvs = index.ReadSymbolRecord(func_id);
+ ProcSym proc(static_cast<SymbolRecordKind>(cvs.kind()));
+ llvm::cantFail(SymbolDeserializer::deserializeAs<ProcSym>(cvs, proc));
+
+ PdbTypeSymId type_id(proc.FunctionType);
+ clang::QualType qt = GetOrCreateType(type_id);
+ if (qt.isNull())
+ return nullptr;
+
+ clang::StorageClass storage = clang::SC_None;
+ if (proc.Kind == SymbolRecordKind::ProcSym)
+ storage = clang::SC_Static;
+
+ const clang::FunctionProtoType *func_type =
+ llvm::dyn_cast<clang::FunctionProtoType>(qt);
+
+ CompilerType func_ct = ToCompilerType(qt);
+
+ llvm::StringRef proc_name = proc.Name;
+ proc_name.consume_front(context_name);
+ proc_name.consume_front("::");
+ clang::FunctionDecl *function_decl =
+ CreateFunctionDecl(func_id, proc_name, proc.FunctionType, func_ct,
+ func_type->getNumParams(), storage, false, parent);
+ if (function_decl == nullptr)
+ return nullptr;
+
+ lldbassert(m_uid_to_decl.count(toOpaqueUid(func_id)) == 0);
+ m_uid_to_decl[toOpaqueUid(func_id)] = function_decl;
+ DeclStatus status;
+ status.resolved = true;
+ status.uid = toOpaqueUid(func_id);
+ m_decl_to_status.insert({function_decl, status});
+
+ return function_decl;
+}
+
+void PdbAstBuilder::CreateFunctionParameters(PdbCompilandSymId func_id,
+ clang::FunctionDecl &function_decl,
+ uint32_t param_count) {
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ CompilandIndexItem *cii = index.compilands().GetCompiland(func_id.modi);
+ CVSymbolArray scope =
+ cii->m_debug_stream.getSymbolArrayForScope(func_id.offset);
+
+ scope.drop_front();
+ auto begin = scope.begin();
+ auto end = scope.end();
+ std::vector<clang::ParmVarDecl *> params;
+ for (uint32_t i = 0; i < param_count && begin != end;) {
+ uint32_t record_offset = begin.offset();
+ CVSymbol sym = *begin++;
+
+ TypeIndex param_type;
+ llvm::StringRef param_name;
+ switch (sym.kind()) {
+ case S_REGREL32: {
+ RegRelativeSym reg(SymbolRecordKind::RegRelativeSym);
+ cantFail(SymbolDeserializer::deserializeAs<RegRelativeSym>(sym, reg));
+ param_type = reg.Type;
+ param_name = reg.Name;
+ break;
+ }
+ case S_REGISTER: {
+ RegisterSym reg(SymbolRecordKind::RegisterSym);
+ cantFail(SymbolDeserializer::deserializeAs<RegisterSym>(sym, reg));
+ param_type = reg.Index;
+ param_name = reg.Name;
+ break;
+ }
+ case S_LOCAL: {
+ LocalSym local(SymbolRecordKind::LocalSym);
+ cantFail(SymbolDeserializer::deserializeAs<LocalSym>(sym, local));
+ if ((local.Flags & LocalSymFlags::IsParameter) == LocalSymFlags::None)
+ continue;
+ param_type = local.Type;
+ param_name = local.Name;
+ break;
+ }
+ case S_BLOCK32:
+ case S_INLINESITE:
+ case S_INLINESITE2:
+ // All parameters should come before the first block/inlinesite. If that
+ // isn't the case, then perhaps this is bad debug info that doesn't
+ // contain information about all parameters.
+ return;
+ default:
+ continue;
+ }
+
+ PdbCompilandSymId param_uid(func_id.modi, record_offset);
+ clang::QualType qt = GetOrCreateType(param_type);
+ if (qt.isNull())
+ return;
+
+ CompilerType param_type_ct = m_clang.GetType(qt);
+ clang::ParmVarDecl *param = m_clang.CreateParameterDeclaration(
+ &function_decl, OptionalClangModuleID(), param_name.str().c_str(),
+ param_type_ct, clang::SC_None, true);
+ lldbassert(m_uid_to_decl.count(toOpaqueUid(param_uid)) == 0);
+
+ m_uid_to_decl[toOpaqueUid(param_uid)] = param;
+ params.push_back(param);
+ ++i;
+ }
+
+ if (!params.empty() && params.size() == param_count)
+ m_clang.SetFunctionParameters(&function_decl, params);
+}
+
+clang::QualType PdbAstBuilder::CreateEnumType(PdbTypeSymId id,
+ const EnumRecord &er) {
+ clang::DeclContext *decl_context = nullptr;
+ std::string uname;
+ std::tie(decl_context, uname) = CreateDeclInfoForType(er, id.index);
+ if (!decl_context)
+ return {};
+
+ clang::QualType underlying_type = GetOrCreateType(er.UnderlyingType);
+ if (underlying_type.isNull())
+ return {};
+
+ Declaration declaration;
+ CompilerType enum_ct = m_clang.CreateEnumerationType(
+ uname, decl_context, OptionalClangModuleID(), declaration,
+ ToCompilerType(underlying_type), er.isScoped());
+
+ TypeSystemClang::StartTagDeclarationDefinition(enum_ct);
+ TypeSystemClang::SetHasExternalStorage(enum_ct.GetOpaqueQualType(), true);
+
+ return clang::QualType::getFromOpaquePtr(enum_ct.GetOpaqueQualType());
+}
+
+clang::QualType PdbAstBuilder::CreateArrayType(const ArrayRecord &ar) {
+ clang::QualType element_type = GetOrCreateType(ar.ElementType);
+
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ uint64_t element_size = GetSizeOfType({ar.ElementType}, index.tpi());
+ if (element_type.isNull() || element_size == 0)
+ return {};
+ uint64_t element_count = ar.Size / element_size;
+
+ CompilerType array_ct = m_clang.CreateArrayType(ToCompilerType(element_type),
+ element_count, false);
+ return clang::QualType::getFromOpaquePtr(array_ct.GetOpaqueQualType());
+}
+
+clang::QualType PdbAstBuilder::CreateFunctionType(
+ TypeIndex args_type_idx, TypeIndex return_type_idx,
+ llvm::codeview::CallingConvention calling_convention) {
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ TpiStream &stream = index.tpi();
+ CVType args_cvt = stream.getType(args_type_idx);
+ ArgListRecord args;
+ llvm::cantFail(
+ TypeDeserializer::deserializeAs<ArgListRecord>(args_cvt, args));
+
+ llvm::ArrayRef<TypeIndex> arg_indices = llvm::ArrayRef(args.ArgIndices);
+ bool is_variadic = IsCVarArgsFunction(arg_indices);
+ if (is_variadic)
+ arg_indices = arg_indices.drop_back();
+
+ std::vector<CompilerType> arg_types;
+ arg_types.reserve(arg_indices.size());
+
+ for (TypeIndex arg_index : arg_indices) {
+ clang::QualType arg_type = GetOrCreateType(arg_index);
+ if (arg_type.isNull())
+ continue;
+ arg_types.push_back(ToCompilerType(arg_type));
+ }
+
+ clang::QualType return_type = GetOrCreateType(return_type_idx);
+ if (return_type.isNull())
+ return {};
+
+ std::optional<clang::CallingConv> cc =
+ TranslateCallingConvention(calling_convention);
+ if (!cc)
+ return {};
+
+ CompilerType return_ct = ToCompilerType(return_type);
+ CompilerType func_sig_ast_type = m_clang.CreateFunctionType(
+ return_ct, arg_types.data(), arg_types.size(), is_variadic, 0, *cc);
+
+ return clang::QualType::getFromOpaquePtr(
+ func_sig_ast_type.GetOpaqueQualType());
+}
+
+static bool isTagDecl(clang::DeclContext &context) {
+ return llvm::isa<clang::TagDecl>(&context);
+}
+
+static bool isFunctionDecl(clang::DeclContext &context) {
+ return llvm::isa<clang::FunctionDecl>(&context);
+}
+
+static bool isBlockDecl(clang::DeclContext &context) {
+ return llvm::isa<clang::BlockDecl>(&context);
+}
+
+void PdbAstBuilder::ParseNamespace(clang::DeclContext &context) {
+ clang::NamespaceDecl *ns = llvm::dyn_cast<clang::NamespaceDecl>(&context);
+ if (m_parsed_namespaces.contains(ns))
+ return;
+ std::string qname = ns->getQualifiedNameAsString();
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ TypeIndex ti{index.tpi().TypeIndexBegin()};
+ for (const CVType &cvt : index.tpi().typeArray()) {
+ PdbTypeSymId tid{ti};
+ ++ti;
+
+ if (!IsTagRecord(cvt))
+ continue;
+
+ CVTagRecord tag = CVTagRecord::create(cvt);
+
+ // Call CreateDeclInfoForType unconditionally so that the namespace info
+ // gets created. But only call CreateRecordType if the namespace name
+ // matches.
+ clang::DeclContext *context = nullptr;
+ std::string uname;
+ std::tie(context, uname) = CreateDeclInfoForType(tag.asTag(), tid.index);
+ if (!context || !context->isNamespace())
+ continue;
+
+ clang::NamespaceDecl *ns = llvm::cast<clang::NamespaceDecl>(context);
+ llvm::StringRef ns_name = ns->getName();
+ if (ns_name.starts_with(qname)) {
+ ns_name = ns_name.drop_front(qname.size());
+ if (ns_name.starts_with("::"))
+ GetOrCreateType(tid);
+ }
+ }
+ ParseAllFunctionsAndNonLocalVars();
+ m_parsed_namespaces.insert(ns);
+}
+
+void PdbAstBuilder::ParseAllTypes() {
+ llvm::call_once(m_parse_all_types, [this]() {
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ TypeIndex ti{index.tpi().TypeIndexBegin()};
+ for (const CVType &cvt : index.tpi().typeArray()) {
+ PdbTypeSymId tid{ti};
+ ++ti;
+
+ if (!IsTagRecord(cvt))
+ continue;
+
+ GetOrCreateType(tid);
+ }
+ });
+}
+
+void PdbAstBuilder::ParseAllFunctionsAndNonLocalVars() {
+ llvm::call_once(m_parse_functions_and_non_local_vars, [this]() {
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ uint32_t module_count = index.dbi().modules().getModuleCount();
+ for (uint16_t modi = 0; modi < module_count; ++modi) {
+ CompilandIndexItem &cii = index.compilands().GetOrCreateCompiland(modi);
+ const CVSymbolArray &symbols = cii.m_debug_stream.getSymbolArray();
+ auto iter = symbols.begin();
+ while (iter != symbols.end()) {
+ PdbCompilandSymId sym_id{modi, iter.offset()};
+
+ switch (iter->kind()) {
+ case S_GPROC32:
+ case S_LPROC32:
+ GetOrCreateFunctionDecl(sym_id);
+ iter = symbols.at(getScopeEndOffset(*iter));
+ break;
+ case S_GDATA32:
+ case S_GTHREAD32:
+ case S_LDATA32:
+ case S_LTHREAD32:
+ GetOrCreateVariableDecl(PdbCompilandSymId(modi, 0), sym_id);
+ ++iter;
+ break;
+ default:
+ ++iter;
+ continue;
+ }
+ }
+ }
+ });
+}
+
+static CVSymbolArray skipFunctionParameters(clang::Decl &decl,
+ const CVSymbolArray &symbols) {
+ clang::FunctionDecl *func_decl = llvm::dyn_cast<clang::FunctionDecl>(&decl);
+ if (!func_decl)
+ return symbols;
+ unsigned int params = func_decl->getNumParams();
+ if (params == 0)
+ return symbols;
+
+ CVSymbolArray result = symbols;
+
+ while (!result.empty()) {
+ if (params == 0)
+ return result;
+
+ CVSymbol sym = *result.begin();
+ result.drop_front();
+
+ if (!isLocalVariableType(sym.kind()))
+ continue;
+
+ --params;
+ }
+ return result;
+}
+
+void PdbAstBuilder::ParseBlockChildren(PdbCompilandSymId block_id) {
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ CVSymbol sym = index.ReadSymbolRecord(block_id);
+ lldbassert(sym.kind() == S_GPROC32 || sym.kind() == S_LPROC32 ||
+ sym.kind() == S_BLOCK32 || sym.kind() == S_INLINESITE);
+ CompilandIndexItem &cii =
+ index.compilands().GetOrCreateCompiland(block_id.modi);
+ CVSymbolArray symbols =
+ cii.m_debug_stream.getSymbolArrayForScope(block_id.offset);
+
+ // Function parameters should already have been created when the function was
+ // parsed.
+ if (sym.kind() == S_GPROC32 || sym.kind() == S_LPROC32)
+ symbols =
+ skipFunctionParameters(*m_uid_to_decl[toOpaqueUid(block_id)], symbols);
+
+ symbols.drop_front();
+ auto begin = symbols.begin();
+ while (begin != symbols.end()) {
+ PdbCompilandSymId child_sym_id(block_id.modi, begin.offset());
+ GetOrCreateSymbolForId(child_sym_id);
+ if (begin->kind() == S_BLOCK32 || begin->kind() == S_INLINESITE) {
+ ParseBlockChildren(child_sym_id);
+ begin = symbols.at(getScopeEndOffset(*begin));
+ }
+ ++begin;
+ }
+}
+
+void PdbAstBuilder::ParseDeclsForSimpleContext(clang::DeclContext &context) {
+
+ clang::Decl *decl = clang::Decl::castFromDeclContext(&context);
+ lldbassert(decl);
+
+ auto iter = m_decl_to_status.find(decl);
+ lldbassert(iter != m_decl_to_status.end());
+
+ if (auto *tag = llvm::dyn_cast<clang::TagDecl>(&context)) {
+ CompleteTagDecl(*tag);
+ return;
+ }
+
+ if (isFunctionDecl(context) || isBlockDecl(context)) {
+ PdbCompilandSymId block_id = PdbSymUid(iter->second.uid).asCompilandSym();
+ ParseBlockChildren(block_id);
+ }
+}
+
+void PdbAstBuilder::ParseDeclsForContext(clang::DeclContext &context) {
+ // Namespaces aren't explicitly represented in the debug info, and the only
+ // way to parse them is to parse all type info, demangling every single type
+ // and trying to reconstruct the DeclContext hierarchy this way. Since this
+ // is an expensive operation, we have to special case it so that we do other
+ // work (such as parsing the items that appear within the namespaces) at the
+ // same time.
+ if (context.isTranslationUnit()) {
+ ParseAllTypes();
+ ParseAllFunctionsAndNonLocalVars();
+ return;
+ }
+
+ if (context.isNamespace()) {
+ ParseNamespace(context);
+ return;
+ }
+
+ if (isTagDecl(context) || isFunctionDecl(context) || isBlockDecl(context)) {
+ ParseDeclsForSimpleContext(context);
+ return;
+ }
+}
+
+CompilerDecl PdbAstBuilder::ToCompilerDecl(clang::Decl &decl) {
+ return m_clang.GetCompilerDecl(&decl);
+}
+
+CompilerType PdbAstBuilder::ToCompilerType(clang::QualType qt) {
+ return {m_clang.weak_from_this(), qt.getAsOpaquePtr()};
+}
+
+CompilerDeclContext
+PdbAstBuilder::ToCompilerDeclContext(clang::DeclContext &context) {
+ return m_clang.CreateDeclContext(&context);
+}
+
+clang::Decl * PdbAstBuilder::FromCompilerDecl(CompilerDecl decl) {
+ return ClangUtil::GetDecl(decl);
+}
+
+clang::DeclContext *
+PdbAstBuilder::FromCompilerDeclContext(CompilerDeclContext context) {
+ return static_cast<clang::DeclContext *>(context.GetOpaqueDeclContext());
+}
+
+void PdbAstBuilder::Dump(Stream &stream) {
+ m_clang.Dump(stream.AsRawOstream());
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h
new file mode 100644
index 000000000000..b7cad30c69c0
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h
@@ -0,0 +1,159 @@
+//===-- PdbAstBuilder.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_NATIVEPDB_PDBASTBUILDER_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBASTBUILDER_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Threading.h"
+
+#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
+
+#include "PdbIndex.h"
+#include "PdbSymUid.h"
+#include <optional>
+
+namespace clang {
+class TagDecl;
+class DeclContext;
+class Decl;
+class QualType;
+class FunctionDecl;
+class NamespaceDecl;
+} // namespace clang
+
+namespace llvm {
+namespace codeview {
+class ProcSym;
+}
+} // namespace llvm
+
+namespace lldb_private {
+class ClangASTImporter;
+class ObjectFile;
+
+namespace npdb {
+class PdbIndex;
+struct VariableInfo;
+
+struct DeclStatus {
+ DeclStatus() = default;
+ DeclStatus(lldb::user_id_t uid, bool resolved)
+ : uid(uid), resolved(resolved) {}
+ lldb::user_id_t uid = 0;
+ bool resolved = false;
+};
+
+class PdbAstBuilder {
+public:
+ // Constructors and Destructors
+ PdbAstBuilder(TypeSystemClang &clang);
+
+ lldb_private::CompilerDeclContext GetTranslationUnitDecl();
+
+ std::optional<lldb_private::CompilerDecl>
+ GetOrCreateDeclForUid(PdbSymUid uid);
+ clang::DeclContext *GetOrCreateDeclContextForUid(PdbSymUid uid);
+ clang::DeclContext *GetParentDeclContext(PdbSymUid uid);
+
+ clang::FunctionDecl *GetOrCreateFunctionDecl(PdbCompilandSymId func_id);
+ clang::FunctionDecl *
+ GetOrCreateInlinedFunctionDecl(PdbCompilandSymId inlinesite_id);
+ clang::BlockDecl *GetOrCreateBlockDecl(PdbCompilandSymId block_id);
+ clang::VarDecl *GetOrCreateVariableDecl(PdbCompilandSymId scope_id,
+ PdbCompilandSymId var_id);
+ clang::VarDecl *GetOrCreateVariableDecl(PdbGlobalSymId var_id);
+ clang::TypedefNameDecl *GetOrCreateTypedefDecl(PdbGlobalSymId id);
+ void ParseDeclsForContext(clang::DeclContext &context);
+
+ clang::QualType GetBasicType(lldb::BasicType type);
+ clang::QualType GetOrCreateType(PdbTypeSymId type);
+
+ bool CompleteTagDecl(clang::TagDecl &tag);
+ bool CompleteType(clang::QualType qt);
+
+ CompilerDecl ToCompilerDecl(clang::Decl &decl);
+ CompilerType ToCompilerType(clang::QualType qt);
+ CompilerDeclContext ToCompilerDeclContext(clang::DeclContext &context);
+ clang::Decl *FromCompilerDecl(CompilerDecl decl);
+ clang::DeclContext *FromCompilerDeclContext(CompilerDeclContext context);
+
+ TypeSystemClang &clang() { return m_clang; }
+ ClangASTImporter &GetClangASTImporter() { return m_importer; }
+
+ void Dump(Stream &stream);
+
+private:
+ clang::Decl *TryGetDecl(PdbSymUid uid) const;
+
+ using TypeIndex = llvm::codeview::TypeIndex;
+
+ clang::QualType
+ CreatePointerType(const llvm::codeview::PointerRecord &pointer);
+ clang::QualType
+ CreateModifierType(const llvm::codeview::ModifierRecord &modifier);
+ clang::QualType CreateArrayType(const llvm::codeview::ArrayRecord &array);
+ clang::QualType CreateRecordType(PdbTypeSymId id,
+ const llvm::codeview::TagRecord &record);
+ clang::QualType CreateEnumType(PdbTypeSymId id,
+ const llvm::codeview::EnumRecord &record);
+ clang::QualType
+ CreateFunctionType(TypeIndex args_type_idx, TypeIndex return_type_idx,
+ llvm::codeview::CallingConvention calling_convention);
+ clang::QualType CreateType(PdbTypeSymId type);
+
+ void CreateFunctionParameters(PdbCompilandSymId func_id,
+ clang::FunctionDecl &function_decl,
+ uint32_t param_count);
+ clang::Decl *GetOrCreateSymbolForId(PdbCompilandSymId id);
+ clang::VarDecl *CreateVariableDecl(PdbSymUid uid,
+ llvm::codeview::CVSymbol sym,
+ clang::DeclContext &scope);
+ clang::NamespaceDecl *GetOrCreateNamespaceDecl(const char *name,
+ clang::DeclContext &context);
+ clang::FunctionDecl *CreateFunctionDeclFromId(PdbTypeSymId func_tid,
+ PdbCompilandSymId func_sid);
+ clang::FunctionDecl *
+ CreateFunctionDecl(PdbCompilandSymId func_id, llvm::StringRef func_name,
+ TypeIndex func_ti, CompilerType func_ct,
+ uint32_t param_count, clang::StorageClass func_storage,
+ bool is_inline, clang::DeclContext *parent);
+ void ParseNamespace(clang::DeclContext &parent);
+ void ParseAllTypes();
+ void ParseAllFunctionsAndNonLocalVars();
+ void ParseDeclsForSimpleContext(clang::DeclContext &context);
+ void ParseBlockChildren(PdbCompilandSymId block_id);
+
+ std::pair<clang::DeclContext *, std::string>
+ CreateDeclInfoForType(const llvm::codeview::TagRecord &record, TypeIndex ti);
+ std::pair<clang::DeclContext *, std::string>
+ CreateDeclInfoForUndecoratedName(llvm::StringRef uname);
+ clang::QualType CreateSimpleType(TypeIndex ti);
+
+ TypeSystemClang &m_clang;
+
+ ClangASTImporter m_importer;
+ llvm::once_flag m_parse_functions_and_non_local_vars;
+ llvm::once_flag m_parse_all_types;
+ llvm::DenseMap<clang::Decl *, DeclStatus> m_decl_to_status;
+ llvm::DenseMap<lldb::user_id_t, clang::Decl *> m_uid_to_decl;
+ llvm::DenseMap<lldb::user_id_t, clang::QualType> m_uid_to_type;
+
+ // From class/struct's opaque_compiler_type_t to a set containing the pairs of
+ // method's name and CompilerType.
+ llvm::DenseMap<lldb::opaque_compiler_type_t,
+ llvm::SmallSet<std::pair<llvm::StringRef, CompilerType>, 8>>
+ m_cxx_record_map;
+ llvm::DenseSet<clang::NamespaceDecl *> m_parsed_namespaces;
+};
+
+} // namespace npdb
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBASTBUILDER_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.cpp
new file mode 100644
index 000000000000..f28509acbf79
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.cpp
@@ -0,0 +1,103 @@
+//===-- PdbFPOProgramToDWARFExpression.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 "PdbFPOProgramToDWARFExpression.h"
+#include "CodeViewRegisterMapping.h"
+
+#include "lldb/Symbol/PostfixExpression.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/Stream.h"
+#include "llvm/ADT/DenseMap.h"
+
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/EnumTables.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::postfix;
+
+static uint32_t ResolveLLDBRegisterNum(llvm::StringRef reg_name, llvm::Triple::ArchType arch_type) {
+ // lookup register name to get lldb register number
+ llvm::codeview::CPUType cpu_type;
+ switch (arch_type) {
+ case llvm::Triple::ArchType::aarch64:
+ cpu_type = llvm::codeview::CPUType::ARM64;
+ break;
+
+ default:
+ cpu_type = llvm::codeview::CPUType::X64;
+ break;
+ }
+
+ llvm::ArrayRef<llvm::EnumEntry<uint16_t>> register_names =
+ llvm::codeview::getRegisterNames(cpu_type);
+ auto it = llvm::find_if(
+ register_names,
+ [&reg_name](const llvm::EnumEntry<uint16_t> &register_entry) {
+ return reg_name.compare_insensitive(register_entry.Name) == 0;
+ });
+
+ if (it == register_names.end())
+ return LLDB_INVALID_REGNUM;
+
+ auto reg_id = static_cast<llvm::codeview::RegisterId>(it->Value);
+ return npdb::GetLLDBRegisterNumber(arch_type, reg_id);
+}
+
+static Node *ResolveFPOProgram(llvm::StringRef program,
+ llvm::StringRef register_name,
+ llvm::Triple::ArchType arch_type,
+ llvm::BumpPtrAllocator &alloc) {
+ std::vector<std::pair<llvm::StringRef, Node *>> parsed =
+ postfix::ParseFPOProgram(program, alloc);
+
+ for (auto it = parsed.begin(), end = parsed.end(); it != end; ++it) {
+ // Emplace valid dependent subtrees to make target assignment independent
+ // from predecessors. Resolve all other SymbolNodes as registers.
+ bool success =
+ ResolveSymbols(it->second, [&](SymbolNode &symbol) -> Node * {
+ for (const auto &pair : llvm::make_range(parsed.begin(), it)) {
+ if (pair.first == symbol.GetName())
+ return pair.second;
+ }
+
+ uint32_t reg_num =
+ ResolveLLDBRegisterNum(symbol.GetName().drop_front(1), arch_type);
+
+ if (reg_num == LLDB_INVALID_REGNUM)
+ return nullptr;
+
+ return MakeNode<RegisterNode>(alloc, reg_num);
+ });
+ if (!success)
+ return nullptr;
+
+ if (it->first == register_name) {
+ // found target assignment program - no need to parse further
+ return it->second;
+ }
+ }
+
+ return nullptr;
+}
+
+bool lldb_private::npdb::TranslateFPOProgramToDWARFExpression(
+ llvm::StringRef program, llvm::StringRef register_name,
+ llvm::Triple::ArchType arch_type, Stream &stream) {
+ llvm::BumpPtrAllocator node_alloc;
+ Node *target_program =
+ ResolveFPOProgram(program, register_name, arch_type, node_alloc);
+ if (target_program == nullptr) {
+ return false;
+ }
+
+ ToDWARF(*target_program, stream);
+ return true;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.h
new file mode 100644
index 000000000000..f6849f2083cc
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.h
@@ -0,0 +1,28 @@
+//===-- PdbFPOProgramToDWARFExpression.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_NATIVEPDB_PDBFPOPROGRAMTODWARFEXPRESSION_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBFPOPROGRAMTODWARFEXPRESSION_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/TargetParser/Triple.h"
+
+namespace lldb_private {
+class Stream;
+
+namespace npdb {
+
+bool TranslateFPOProgramToDWARFExpression(llvm::StringRef program,
+ llvm::StringRef register_name,
+ llvm::Triple::ArchType arch_type,
+ lldb_private::Stream &stream);
+
+} // namespace npdb
+} // namespace lldb_private
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp
new file mode 100644
index 000000000000..ea778fc6cca6
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp
@@ -0,0 +1,196 @@
+//===-- PdbIndex.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 "PdbIndex.h"
+#include "PdbUtil.h"
+
+#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
+#include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
+#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/Error.h"
+
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/lldb-defines.h"
+#include <optional>
+
+using namespace lldb_private;
+using namespace lldb_private::npdb;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+PdbIndex::PdbIndex() : m_cus(*this), m_va_to_modi(m_allocator) {}
+
+#define ASSIGN_PTR_OR_RETURN(result_ptr, expr) \
+ { \
+ auto expected_result = expr; \
+ if (!expected_result) \
+ return expected_result.takeError(); \
+ result_ptr = &expected_result.get(); \
+ }
+
+llvm::Expected<std::unique_ptr<PdbIndex>>
+PdbIndex::create(llvm::pdb::PDBFile *file) {
+ lldbassert(file);
+
+ std::unique_ptr<PdbIndex> result(new PdbIndex());
+ ASSIGN_PTR_OR_RETURN(result->m_dbi, file->getPDBDbiStream());
+ ASSIGN_PTR_OR_RETURN(result->m_tpi, file->getPDBTpiStream());
+ ASSIGN_PTR_OR_RETURN(result->m_ipi, file->getPDBIpiStream());
+ ASSIGN_PTR_OR_RETURN(result->m_info, file->getPDBInfoStream());
+ ASSIGN_PTR_OR_RETURN(result->m_publics, file->getPDBPublicsStream());
+ ASSIGN_PTR_OR_RETURN(result->m_globals, file->getPDBGlobalsStream());
+ ASSIGN_PTR_OR_RETURN(result->m_symrecords, file->getPDBSymbolStream());
+
+ result->m_tpi->buildHashMap();
+
+ result->m_file = file;
+
+ return std::move(result);
+}
+
+lldb::addr_t PdbIndex::MakeVirtualAddress(uint16_t segment,
+ uint32_t offset) const {
+ uint32_t max_section = dbi().getSectionHeaders().size();
+ // Segment indices are 1-based.
+ // If this is an absolute symbol, it's indicated by the magic section index
+ // |max_section+1|. In this case, the offset is meaningless, so just return.
+ if (segment == 0 || segment > max_section)
+ return LLDB_INVALID_ADDRESS;
+
+ const llvm::object::coff_section &cs = dbi().getSectionHeaders()[segment - 1];
+ return m_load_address + static_cast<lldb::addr_t>(cs.VirtualAddress) +
+ static_cast<lldb::addr_t>(offset);
+}
+
+std::optional<uint16_t> PdbIndex::GetModuleIndexForAddr(uint16_t segment,
+ uint32_t offset) const {
+ return GetModuleIndexForVa(MakeVirtualAddress(segment, offset));
+}
+
+std::optional<uint16_t> PdbIndex::GetModuleIndexForVa(lldb::addr_t va) const {
+ auto iter = m_va_to_modi.find(va);
+ if (iter == m_va_to_modi.end())
+ return std::nullopt;
+
+ return iter.value();
+}
+
+void PdbIndex::ParseSectionContribs() {
+ class Visitor : public ISectionContribVisitor {
+ PdbIndex &m_ctx;
+ llvm::IntervalMap<uint64_t, uint16_t> &m_imap;
+
+ public:
+ Visitor(PdbIndex &ctx, llvm::IntervalMap<uint64_t, uint16_t> &imap)
+ : m_ctx(ctx), m_imap(imap) {}
+
+ void visit(const SectionContrib &C) override {
+ if (C.Size == 0)
+ return;
+
+ uint64_t va = m_ctx.MakeVirtualAddress(C.ISect, C.Off);
+ if (va == LLDB_INVALID_ADDRESS)
+ return;
+ uint64_t end = va + C.Size;
+ // IntervalMap's start and end represent a closed range, not a half-open
+ // range, so we have to subtract 1.
+ m_imap.insert(va, end - 1, C.Imod);
+ }
+ void visit(const SectionContrib2 &C) override { visit(C.Base); }
+ };
+ Visitor v(*this, m_va_to_modi);
+ dbi().visitSectionContributions(v);
+}
+
+void PdbIndex::BuildAddrToSymbolMap(CompilandIndexItem &cci) {
+ lldbassert(cci.m_symbols_by_va.empty() &&
+ "Addr to symbol map is already built!");
+ uint16_t modi = cci.m_id.modi;
+ const CVSymbolArray &syms = cci.m_debug_stream.getSymbolArray();
+ for (auto iter = syms.begin(); iter != syms.end(); ++iter) {
+ if (!SymbolHasAddress(*iter))
+ continue;
+
+ SegmentOffset so = GetSegmentAndOffset(*iter);
+ lldb::addr_t va = MakeVirtualAddress(so.segment, so.offset);
+ if (va == LLDB_INVALID_ADDRESS)
+ continue;
+
+ PdbCompilandSymId cu_sym_id(modi, iter.offset());
+
+ // It's rare, but we could have multiple symbols with the same address
+ // because of identical comdat folding. Right now, the first one will win.
+ cci.m_symbols_by_va.insert(std::make_pair(va, PdbSymUid(cu_sym_id)));
+ }
+}
+
+std::vector<SymbolAndUid> PdbIndex::FindSymbolsByVa(lldb::addr_t va) {
+ std::vector<SymbolAndUid> result;
+
+ std::optional<uint16_t> modi = GetModuleIndexForVa(va);
+ if (!modi)
+ return result;
+
+ CompilandIndexItem &cci = compilands().GetOrCreateCompiland(*modi);
+ if (cci.m_symbols_by_va.empty())
+ BuildAddrToSymbolMap(cci);
+
+ // The map is sorted by starting address of the symbol. So for example
+ // we could (in theory) have this situation
+ //
+ // [------------------]
+ // [----------]
+ // [-----------]
+ // [-------------]
+ // [----]
+ // [-----]
+ // ^ Address we're searching for
+ // In order to find this, we use the upper_bound of the key value which would
+ // be the first symbol whose starting address is higher than the element we're
+ // searching for.
+
+ auto ub = cci.m_symbols_by_va.upper_bound(va);
+
+ for (auto iter = cci.m_symbols_by_va.begin(); iter != ub; ++iter) {
+ PdbCompilandSymId cu_sym_id = iter->second.asCompilandSym();
+ CVSymbol sym = ReadSymbolRecord(cu_sym_id);
+
+ SegmentOffsetLength sol;
+ if (SymbolIsCode(sym))
+ sol = GetSegmentOffsetAndLength(sym);
+ else
+ sol.so = GetSegmentAndOffset(sym);
+
+ lldb::addr_t start = MakeVirtualAddress(sol.so.segment, sol.so.offset);
+ if (start == LLDB_INVALID_ADDRESS)
+ continue;
+
+ lldb::addr_t end = start + sol.length;
+ if (va >= start && va < end)
+ result.push_back({std::move(sym), iter->second});
+ }
+
+ return result;
+}
+
+CVSymbol PdbIndex::ReadSymbolRecord(PdbCompilandSymId cu_sym) const {
+ const CompilandIndexItem *cci = compilands().GetCompiland(cu_sym.modi);
+ auto iter = cci->m_debug_stream.getSymbolArray().at(cu_sym.offset);
+ lldbassert(iter != cci->m_debug_stream.getSymbolArray().end());
+ return *iter;
+}
+
+CVSymbol PdbIndex::ReadSymbolRecord(PdbGlobalSymId global) const {
+ return symrecords().readRecord(global.offset);
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.h
new file mode 100644
index 000000000000..796aa4c8dfd1
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.h
@@ -0,0 +1,159 @@
+//===-- PdbIndex.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_NATIVEPDB_PDBINDEX_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBINDEX_H
+
+#include "lldb/lldb-types.h"
+#include "llvm/ADT/IntervalMap.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/PDBTypes.h"
+
+#include "CompileUnitIndex.h"
+#include "PdbSymUid.h"
+
+#include <map>
+#include <memory>
+#include <optional>
+
+namespace llvm {
+namespace pdb {
+class DbiStream;
+class TpiStream;
+class InfoStream;
+class PublicsStream;
+class GlobalsStream;
+class SymbolStream;
+} // namespace pdb
+} // namespace llvm
+
+namespace lldb_private {
+namespace npdb {
+struct SegmentOffset;
+
+/// PdbIndex - Lazy access to the important parts of a PDB file.
+///
+/// This is a layer on top of LLVM's native PDB support libraries which cache
+/// certain data when it is accessed the first time. The entire PDB file is
+/// mapped into memory, and the underlying support libraries vend out memory
+/// that is always backed by the file, so it is safe to hold StringRefs and
+/// ArrayRefs into the backing memory as long as the PdbIndex instance is
+/// alive.
+class PdbIndex {
+
+ /// The underlying PDB file.
+ llvm::pdb::PDBFile *m_file = nullptr;
+
+ /// The DBI stream. This contains general high level information about the
+ /// features present in the PDB file, compile units (such as the information
+ /// necessary to locate full symbol information for each compile unit),
+ /// section contributions, and other data which is not specifically symbol or
+ /// type records.
+ llvm::pdb::DbiStream *m_dbi = nullptr;
+
+ /// TPI (types) and IPI (indices) streams. These are both in the exact same
+ /// format with different data. Most type records are stored in the TPI
+ /// stream but certain specific types of records are stored in the IPI stream.
+ /// The IPI stream records can refer to the records in the TPI stream, but not
+ /// the other way around.
+ llvm::pdb::TpiStream *m_tpi = nullptr;
+ llvm::pdb::TpiStream *m_ipi = nullptr;
+
+ /// This is called the "PDB Stream" in the Microsoft reference implementation.
+ /// It contains information about the structure of the file, as well as fields
+ /// used to match EXE and PDB.
+ llvm::pdb::InfoStream *m_info = nullptr;
+
+ /// Publics stream. Is actually a serialized hash table where the keys are
+ /// addresses of symbols in the executable, and values are a record containing
+ /// mangled names and an index which can be used to locate more detailed info
+ /// about the symbol in the Symbol Records stream. The publics stream only
+ /// contains info about externally visible symbols.
+ llvm::pdb::PublicsStream *m_publics = nullptr;
+
+ /// Globals stream. Contrary to its name, this does not contain information
+ /// about all "global variables" or "global functions". Rather, it is the
+ /// "global symbol table", i.e. it contains information about *every* symbol
+ /// in the executable. It is a hash table keyed on name, whose values are
+ /// indices into the symbol records stream to find the full record.
+ llvm::pdb::GlobalsStream *m_globals = nullptr;
+
+ /// Symbol records stream. The publics and globals stream refer to records
+ /// in this stream. For some records, like constants and typedefs, the
+ /// complete record lives in this stream. For other symbol types, such as
+ /// functions, data, and other things that have been materialied into a
+ /// specific compile unit, the records here simply provide a reference
+ /// necessary to locate the full information.
+ llvm::pdb::SymbolStream *m_symrecords = nullptr;
+
+ /// Index of all compile units, mapping identifier to |CompilandIndexItem|
+ /// instance.
+ CompileUnitIndex m_cus;
+
+ /// An allocator for the interval maps
+ llvm::IntervalMap<lldb::addr_t, uint32_t>::Allocator m_allocator;
+
+ /// Maps virtual address to module index
+ llvm::IntervalMap<lldb::addr_t, uint16_t> m_va_to_modi;
+
+ /// The address at which the program has been loaded into memory.
+ lldb::addr_t m_load_address = 0;
+
+ PdbIndex();
+
+ void BuildAddrToSymbolMap(CompilandIndexItem &cci);
+
+public:
+ static llvm::Expected<std::unique_ptr<PdbIndex>> create(llvm::pdb::PDBFile *);
+
+ void SetLoadAddress(lldb::addr_t addr) { m_load_address = addr; }
+ lldb::addr_t GetLoadAddress() const { return m_load_address; }
+ void ParseSectionContribs();
+
+ llvm::pdb::PDBFile &pdb() { return *m_file; }
+ const llvm::pdb::PDBFile &pdb() const { return *m_file; }
+
+ llvm::pdb::DbiStream &dbi() { return *m_dbi; }
+ const llvm::pdb::DbiStream &dbi() const { return *m_dbi; }
+
+ llvm::pdb::TpiStream &tpi() { return *m_tpi; }
+ const llvm::pdb::TpiStream &tpi() const { return *m_tpi; }
+
+ llvm::pdb::TpiStream &ipi() { return *m_ipi; }
+ const llvm::pdb::TpiStream &ipi() const { return *m_ipi; }
+
+ llvm::pdb::InfoStream &info() { return *m_info; }
+ const llvm::pdb::InfoStream &info() const { return *m_info; }
+
+ llvm::pdb::PublicsStream &publics() { return *m_publics; }
+ const llvm::pdb::PublicsStream &publics() const { return *m_publics; }
+
+ llvm::pdb::GlobalsStream &globals() { return *m_globals; }
+ const llvm::pdb::GlobalsStream &globals() const { return *m_globals; }
+
+ llvm::pdb::SymbolStream &symrecords() { return *m_symrecords; }
+ const llvm::pdb::SymbolStream &symrecords() const { return *m_symrecords; }
+
+ CompileUnitIndex &compilands() { return m_cus; }
+ const CompileUnitIndex &compilands() const { return m_cus; }
+
+ lldb::addr_t MakeVirtualAddress(uint16_t segment, uint32_t offset) const;
+
+ std::vector<SymbolAndUid> FindSymbolsByVa(lldb::addr_t va);
+
+ llvm::codeview::CVSymbol ReadSymbolRecord(PdbCompilandSymId cu_sym) const;
+ llvm::codeview::CVSymbol ReadSymbolRecord(PdbGlobalSymId global) const;
+
+ std::optional<uint16_t> GetModuleIndexForAddr(uint16_t segment,
+ uint32_t offset) const;
+ std::optional<uint16_t> GetModuleIndexForVa(lldb::addr_t va) const;
+};
+} // namespace npdb
+} // namespace lldb_private
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbSymUid.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbSymUid.cpp
new file mode 100644
index 000000000000..67397d707110
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbSymUid.cpp
@@ -0,0 +1,160 @@
+//===-- PdbSymUid.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 "PdbSymUid.h"
+
+using namespace lldb_private;
+using namespace lldb_private::npdb;
+using namespace llvm::codeview;
+
+namespace {
+struct GenericIdRepr {
+ uint64_t tag : 4;
+ uint64_t data : 60;
+};
+
+struct CompilandIdRepr {
+ uint64_t tag : 4;
+ uint64_t modi : 16;
+ uint64_t unused : 44;
+};
+
+struct CompilandSymIdRepr {
+ uint64_t tag : 4;
+ uint64_t modi : 16;
+ uint64_t offset : 32;
+ uint64_t unused : 12;
+};
+
+struct GlobalSymIdRepr {
+ uint64_t tag : 4;
+ uint64_t offset : 32;
+ uint64_t pub : 1;
+ uint64_t unused : 27;
+};
+
+struct TypeSymIdRepr {
+ uint64_t tag : 4;
+ uint64_t index : 32;
+ uint64_t ipi : 1;
+ uint64_t unused : 27;
+};
+
+struct FieldListMemberIdRepr {
+ uint64_t tag : 4;
+ uint64_t index : 32;
+ uint64_t offset : 16;
+ uint64_t unused : 12;
+};
+
+static_assert(sizeof(CompilandIdRepr) == 8, "Invalid structure size!");
+static_assert(sizeof(CompilandSymIdRepr) == 8, "Invalid structure size!");
+static_assert(sizeof(GlobalSymIdRepr) == 8, "Invalid structure size!");
+static_assert(sizeof(TypeSymIdRepr) == 8, "Invalid structure size!");
+static_assert(sizeof(FieldListMemberIdRepr) == 8, "Invalid structure size!");
+} // namespace
+
+template <typename OutT, typename InT> static OutT repr_cast(const InT &value) {
+ OutT result;
+ ::memcpy(&result, &value, sizeof(value));
+ return result;
+}
+
+PdbSymUid::PdbSymUid(const PdbCompilandId &cid) {
+ CompilandIdRepr repr;
+ ::memset(&repr, 0, sizeof(repr));
+ repr.modi = cid.modi;
+ repr.tag = static_cast<uint64_t>(PdbSymUidKind::Compiland);
+ m_repr = repr_cast<uint64_t>(repr);
+}
+
+PdbSymUid::PdbSymUid(const PdbCompilandSymId &csid) {
+ CompilandSymIdRepr repr;
+ ::memset(&repr, 0, sizeof(repr));
+ repr.modi = csid.modi;
+ repr.offset = csid.offset;
+ repr.tag = static_cast<uint64_t>(PdbSymUidKind::CompilandSym);
+ m_repr = repr_cast<uint64_t>(repr);
+}
+
+PdbSymUid::PdbSymUid(const PdbGlobalSymId &gsid) {
+ GlobalSymIdRepr repr;
+ ::memset(&repr, 0, sizeof(repr));
+ repr.pub = gsid.is_public;
+ repr.offset = gsid.offset;
+ repr.tag = static_cast<uint64_t>(PdbSymUidKind::GlobalSym);
+ m_repr = repr_cast<uint64_t>(repr);
+}
+
+PdbSymUid::PdbSymUid(const PdbTypeSymId &tsid) {
+ TypeSymIdRepr repr;
+ ::memset(&repr, 0, sizeof(repr));
+ repr.index = tsid.index.getIndex();
+ repr.ipi = tsid.is_ipi;
+ repr.tag = static_cast<uint64_t>(PdbSymUidKind::Type);
+ m_repr = repr_cast<uint64_t>(repr);
+}
+
+PdbSymUid::PdbSymUid(const PdbFieldListMemberId &flmid) {
+ FieldListMemberIdRepr repr;
+ ::memset(&repr, 0, sizeof(repr));
+ repr.index = flmid.index.getIndex();
+ repr.offset = flmid.offset;
+ repr.tag = static_cast<uint64_t>(PdbSymUidKind::FieldListMember);
+ m_repr = repr_cast<uint64_t>(repr);
+}
+
+PdbSymUidKind PdbSymUid::kind() const {
+ GenericIdRepr generic = repr_cast<GenericIdRepr>(m_repr);
+ return static_cast<PdbSymUidKind>(generic.tag);
+}
+
+PdbCompilandId PdbSymUid::asCompiland() const {
+ assert(kind() == PdbSymUidKind::Compiland);
+ auto repr = repr_cast<CompilandIdRepr>(m_repr);
+ PdbCompilandId result;
+ result.modi = repr.modi;
+ return result;
+}
+
+PdbCompilandSymId PdbSymUid::asCompilandSym() const {
+ assert(kind() == PdbSymUidKind::CompilandSym);
+ auto repr = repr_cast<CompilandSymIdRepr>(m_repr);
+ PdbCompilandSymId result;
+ result.modi = repr.modi;
+ result.offset = repr.offset;
+ return result;
+}
+
+PdbGlobalSymId PdbSymUid::asGlobalSym() const {
+ assert(kind() == PdbSymUidKind::GlobalSym ||
+ kind() == PdbSymUidKind::PublicSym);
+ auto repr = repr_cast<GlobalSymIdRepr>(m_repr);
+ PdbGlobalSymId result;
+ result.is_public = repr.pub;
+ result.offset = repr.offset;
+ return result;
+}
+
+PdbTypeSymId PdbSymUid::asTypeSym() const {
+ assert(kind() == PdbSymUidKind::Type);
+ auto repr = repr_cast<TypeSymIdRepr>(m_repr);
+ PdbTypeSymId result;
+ result.index.setIndex(repr.index);
+ result.is_ipi = repr.ipi;
+ return result;
+}
+
+PdbFieldListMemberId PdbSymUid::asFieldListMember() const {
+ assert(kind() == PdbSymUidKind::FieldListMember);
+ auto repr = repr_cast<FieldListMemberIdRepr>(m_repr);
+ PdbFieldListMemberId result;
+ result.index.setIndex(repr.index);
+ result.offset = repr.offset;
+ return result;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbSymUid.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbSymUid.h
new file mode 100644
index 000000000000..3accd38d710e
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbSymUid.h
@@ -0,0 +1,125 @@
+//===-- PdbSymUid.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
+//
+//===----------------------------------------------------------------------===//
+// A unique identification scheme for Pdb records.
+// The scheme is to partition a 64-bit integer into an 8-bit tag field, which
+// will contain some value from the PDB_SymType enumeration. The format of the
+// other 48-bits depend on the tag, but must be sufficient to locate the
+// corresponding entry in the underlying PDB file quickly. For example, for
+// a compile unit, we use 2 bytes to represent the index, which allows fast
+// access to the compile unit's information.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBSYMUID_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBSYMUID_H
+
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/PDB/PDBTypes.h"
+#include "llvm/Support/Compiler.h"
+
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/lldb-types.h"
+
+namespace lldb_private {
+namespace npdb {
+
+enum class PdbSymUidKind : uint8_t {
+ Compiland,
+ CompilandSym,
+ PublicSym,
+ GlobalSym,
+ Type,
+ FieldListMember
+};
+
+struct PdbCompilandId {
+ // 0-based index of module in PDB
+ uint16_t modi;
+};
+
+struct PdbCompilandSymId {
+ PdbCompilandSymId() = default;
+ PdbCompilandSymId(uint16_t modi, uint32_t offset)
+ : modi(modi), offset(offset) {}
+ // 0-based index of module in PDB
+ uint16_t modi = 0;
+
+ // Offset of symbol's record in module stream. This is
+ // offset by 4 from the CVSymbolArray's notion of offset
+ // due to the debug magic at the beginning of the stream.
+ uint32_t offset = 0;
+};
+
+struct PdbGlobalSymId {
+ PdbGlobalSymId() = default;
+ PdbGlobalSymId(uint32_t offset, bool is_public)
+ : offset(offset), is_public(is_public) {}
+
+ // Offset of symbol's record in globals or publics stream.
+ uint32_t offset = 0;
+
+ // True if this symbol is in the public stream, false if it's in the globals
+ // stream.
+ bool is_public = false;
+};
+
+struct PdbTypeSymId {
+ PdbTypeSymId() = default;
+ PdbTypeSymId(llvm::codeview::TypeIndex index, bool is_ipi = false)
+ : index(index), is_ipi(is_ipi) {}
+
+ // The index of the of the type in the TPI or IPI stream.
+ llvm::codeview::TypeIndex index;
+
+ // True if this symbol comes from the IPI stream, false if it's from the TPI
+ // stream.
+ bool is_ipi = false;
+};
+
+struct PdbFieldListMemberId {
+ // The TypeIndex of the LF_FIELDLIST record.
+ llvm::codeview::TypeIndex index;
+
+ // The offset from the beginning of the LF_FIELDLIST record to this record.
+ uint16_t offset = 0;
+};
+
+class PdbSymUid {
+ uint64_t m_repr = 0;
+
+public:
+ PdbSymUid() = default;
+ PdbSymUid(uint64_t repr) : m_repr(repr) {}
+ PdbSymUid(const PdbCompilandId &cid);
+ PdbSymUid(const PdbCompilandSymId &csid);
+ PdbSymUid(const PdbGlobalSymId &gsid);
+ PdbSymUid(const PdbTypeSymId &tsid);
+ PdbSymUid(const PdbFieldListMemberId &flmid);
+
+ uint64_t toOpaqueId() const { return m_repr; }
+
+ PdbSymUidKind kind() const;
+
+ PdbCompilandId asCompiland() const;
+ PdbCompilandSymId asCompilandSym() const;
+ PdbGlobalSymId asGlobalSym() const;
+ PdbTypeSymId asTypeSym() const;
+ PdbFieldListMemberId asFieldListMember() const;
+};
+
+template <typename T> uint64_t toOpaqueUid(const T &cid) {
+ return PdbSymUid(cid).toOpaqueId();
+}
+
+struct SymbolAndUid {
+ llvm::codeview::CVSymbol sym;
+ PdbSymUid uid;
+};
+} // namespace npdb
+} // namespace lldb_private
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
new file mode 100644
index 000000000000..888bd89a7262
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
@@ -0,0 +1,1120 @@
+//===-- PdbUtil.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 "PdbUtil.h"
+
+#include "DWARFLocationExpression.h"
+#include "PdbIndex.h"
+#include "PdbSymUid.h"
+
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+
+#include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h"
+#include "Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.h"
+#include "lldb/Symbol/Block.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/lldb-enumerations.h"
+
+using namespace lldb_private;
+using namespace lldb_private::npdb;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+// The returned range list is guaranteed to be sorted and no overlaps between
+// adjacent ranges because fields in LocalVariableAddrGap are unsigned integers.
+static Variable::RangeList
+MakeRangeList(const PdbIndex &index, const LocalVariableAddrRange &range,
+ llvm::ArrayRef<LocalVariableAddrGap> gaps) {
+ lldb::addr_t start =
+ index.MakeVirtualAddress(range.ISectStart, range.OffsetStart);
+ if (start == LLDB_INVALID_ADDRESS)
+ return {};
+ lldb::addr_t end = start + range.Range;
+
+ Variable::RangeList result;
+ while (!gaps.empty()) {
+ const LocalVariableAddrGap &gap = gaps.front();
+ lldb::addr_t gap_start = start + gap.GapStartOffset;
+ result.Append(start, gap_start - start);
+ start = gap_start + gap.Range;
+ gaps = gaps.drop_front();
+ }
+
+ result.Append(start, end - start);
+ return result;
+}
+
+namespace {
+struct MemberLocations {
+ std::map<uint64_t, MemberValLocation> offset_to_location;
+ DWARFExpression expr;
+ bool is_dwarf = false;
+
+ MemberLocations() = default;
+ MemberLocations(const DWARFExpression &expr) : expr(expr), is_dwarf(true) {}
+ MemberLocations(uint64_t offset, const MemberValLocation &member_loc) {
+ insert(offset, member_loc);
+ }
+
+ void insert(uint64_t offset, const MemberValLocation &member_loc) {
+ offset_to_location[offset] = member_loc;
+ }
+
+ struct Comparator {
+ public:
+ bool operator()(const MemberLocations &, const MemberLocations &) const {
+ return false;
+ }
+ };
+};
+
+// A range map with address ranges to a map of pair of offset and locaitons.
+typedef RangeDataVector<lldb::addr_t, lldb::addr_t, MemberLocations, 0,
+ MemberLocations::Comparator>
+ RangeMap;
+
+void AddMemberLocationRanges(RangeMap &location_map, uint64_t offset,
+ MemberValLocation member_loc,
+ const Variable::RangeList &ranges) {
+ RangeMap new_location_map;
+ auto add_overlap_region = [&](lldb::addr_t base, lldb::addr_t end,
+ RangeMap::Entry *entry) {
+ RangeMap::Entry overlap_region = {base, end - base, entry->data};
+ overlap_region.data.insert(offset, member_loc);
+ new_location_map.Append(overlap_region);
+ };
+
+ for (const auto &range : ranges) {
+ lldb::addr_t base = range.GetRangeBase();
+ lldb::addr_t end = range.GetRangeEnd();
+ uint32_t base_idx = location_map.FindEntryIndexThatContainsOrFollows(base);
+ while (auto *entry = location_map.GetMutableEntryAtIndex(base_idx)) {
+ if (base >= end || entry->base >= end)
+ break;
+ if (entry->data.is_dwarf)
+ base = entry->GetRangeEnd();
+ else {
+ lldb::addr_t entry_end = entry->GetRangeEnd();
+ if (base > entry->base) {
+ if (end < entry_end)
+ new_location_map.Append({end, entry_end - end, entry->data});
+ add_overlap_region(base, end < entry_end ? end : entry_end, entry);
+ entry->SetRangeEnd(base);
+ } else if (base < entry->base) {
+ new_location_map.Append(
+ {base, entry->base - base, {offset, member_loc}});
+ if (entry_end == end)
+ entry->data.insert(offset, member_loc);
+ else {
+ add_overlap_region(entry->base, end, entry);
+ entry->ShrinkFront(end - entry->base);
+ }
+ } else {
+ if (end < entry_end) {
+ new_location_map.Append({end, entry_end, entry->data});
+ entry->SetRangeEnd(end);
+ }
+ entry->data.insert(offset, member_loc);
+ }
+ base = entry_end;
+ }
+ ++base_idx;
+ }
+ if (base >= end)
+ continue;
+ new_location_map.Append({base, end - base, {offset, member_loc}});
+ }
+ for (const auto &entry : new_location_map)
+ location_map.Append(entry);
+ if (!new_location_map.IsEmpty())
+ location_map.Sort();
+}
+
+void AddDwarfRange(RangeMap &location_map, const DWARFExpression &expr,
+ const Variable::RangeList &ranges) {
+ if (!expr.IsValid())
+ return;
+ RangeMap new_location_map;
+ for (const auto &range : ranges) {
+ lldb::addr_t base = range.GetRangeBase();
+ lldb::addr_t end = range.GetRangeEnd();
+ uint32_t base_idx = location_map.FindEntryIndexThatContains(base);
+ uint32_t end_idx = location_map.FindEntryIndexThatContains(end - 1);
+ // range is within an entry.
+ if (base_idx == end_idx && base_idx != UINT32_MAX) {
+ auto *entry = location_map.GetMutableEntryAtIndex(base_idx);
+ if (base > entry->base) {
+ new_location_map.Append({entry->base, base - entry->base, entry->data});
+ entry->ShrinkFront(base - entry->base);
+ }
+ if (end == entry->GetRangeEnd())
+ entry->data = expr;
+ else {
+ entry->ShrinkFront(end - base);
+ new_location_map.Append({base, end - base, expr});
+ }
+ continue;
+ }
+ base_idx = location_map.FindEntryIndexThatContainsOrFollows(base);
+ if (auto *entry = location_map.GetMutableEntryAtIndex(base_idx)) {
+ if (entry->Contains(base) && entry->base != base) {
+ entry->SetRangeEnd(base);
+ ++base_idx;
+ }
+ }
+ end_idx = location_map.FindEntryIndexThatContainsOrFollows(end - 1);
+ if (auto *entry = location_map.GetMutableEntryAtIndex(end_idx)) {
+ if (entry->Contains(end - 1)) {
+ if (entry->GetRangeEnd() == end)
+ ++end_idx;
+ else
+ entry->ShrinkFront(end - entry->base);
+ }
+ }
+
+ if (end_idx == UINT32_MAX)
+ end_idx = location_map.GetSize();
+ // Erase existing ranges covered by new range.
+ location_map.Erase(base_idx, end_idx);
+ new_location_map.Append({base, end - base, expr});
+ }
+
+ for (const auto &entry : new_location_map)
+ location_map.Append(entry);
+ location_map.Sort();
+}
+} // namespace
+
+CVTagRecord CVTagRecord::create(CVType type) {
+ assert(IsTagRecord(type) && "type is not a tag record!");
+ switch (type.kind()) {
+ case LF_CLASS:
+ case LF_STRUCTURE:
+ case LF_INTERFACE: {
+ ClassRecord cr;
+ llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(type, cr));
+ return CVTagRecord(std::move(cr));
+ }
+ case LF_UNION: {
+ UnionRecord ur;
+ llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(type, ur));
+ return CVTagRecord(std::move(ur));
+ }
+ case LF_ENUM: {
+ EnumRecord er;
+ llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(type, er));
+ return CVTagRecord(std::move(er));
+ }
+ default:
+ llvm_unreachable("Unreachable!");
+ }
+}
+
+CVTagRecord::CVTagRecord(ClassRecord &&c)
+ : cvclass(std::move(c)),
+ m_kind(cvclass.Kind == TypeRecordKind::Struct ? Struct : Class) {}
+CVTagRecord::CVTagRecord(UnionRecord &&u)
+ : cvunion(std::move(u)), m_kind(Union) {}
+CVTagRecord::CVTagRecord(EnumRecord &&e) : cvenum(std::move(e)), m_kind(Enum) {}
+
+PDB_SymType lldb_private::npdb::CVSymToPDBSym(SymbolKind kind) {
+ switch (kind) {
+ case S_COMPILE3:
+ case S_OBJNAME:
+ return PDB_SymType::CompilandDetails;
+ case S_ENVBLOCK:
+ return PDB_SymType::CompilandEnv;
+ case S_THUNK32:
+ case S_TRAMPOLINE:
+ return PDB_SymType::Thunk;
+ case S_COFFGROUP:
+ return PDB_SymType::CoffGroup;
+ case S_EXPORT:
+ return PDB_SymType::Export;
+ case S_LPROC32:
+ case S_GPROC32:
+ case S_LPROC32_DPC:
+ return PDB_SymType::Function;
+ case S_PUB32:
+ return PDB_SymType::PublicSymbol;
+ case S_INLINESITE:
+ return PDB_SymType::InlineSite;
+ case S_LOCAL:
+ case S_BPREL32:
+ case S_REGREL32:
+ case S_MANCONSTANT:
+ case S_CONSTANT:
+ case S_LDATA32:
+ case S_GDATA32:
+ case S_LMANDATA:
+ case S_GMANDATA:
+ case S_LTHREAD32:
+ case S_GTHREAD32:
+ return PDB_SymType::Data;
+ case S_BLOCK32:
+ return PDB_SymType::Block;
+ case S_LABEL32:
+ return PDB_SymType::Label;
+ case S_CALLSITEINFO:
+ return PDB_SymType::CallSite;
+ case S_HEAPALLOCSITE:
+ return PDB_SymType::HeapAllocationSite;
+ case S_CALLEES:
+ return PDB_SymType::Callee;
+ case S_CALLERS:
+ return PDB_SymType::Caller;
+ default:
+ lldbassert(false && "Invalid symbol record kind!");
+ }
+ return PDB_SymType::None;
+}
+
+PDB_SymType lldb_private::npdb::CVTypeToPDBType(TypeLeafKind kind) {
+ switch (kind) {
+ case LF_ARRAY:
+ return PDB_SymType::ArrayType;
+ case LF_ARGLIST:
+ return PDB_SymType::FunctionSig;
+ case LF_BCLASS:
+ return PDB_SymType::BaseClass;
+ case LF_BINTERFACE:
+ return PDB_SymType::BaseInterface;
+ case LF_CLASS:
+ case LF_STRUCTURE:
+ case LF_INTERFACE:
+ case LF_UNION:
+ return PDB_SymType::UDT;
+ case LF_POINTER:
+ return PDB_SymType::PointerType;
+ case LF_ENUM:
+ return PDB_SymType::Enum;
+ case LF_PROCEDURE:
+ return PDB_SymType::FunctionSig;
+ case LF_BITFIELD:
+ return PDB_SymType::BuiltinType;
+ default:
+ lldbassert(false && "Invalid type record kind!");
+ }
+ return PDB_SymType::None;
+}
+
+bool lldb_private::npdb::SymbolHasAddress(const CVSymbol &sym) {
+ switch (sym.kind()) {
+ case S_GPROC32:
+ case S_LPROC32:
+ case S_GPROC32_ID:
+ case S_LPROC32_ID:
+ case S_LPROC32_DPC:
+ case S_LPROC32_DPC_ID:
+ case S_THUNK32:
+ case S_TRAMPOLINE:
+ case S_COFFGROUP:
+ case S_BLOCK32:
+ case S_LABEL32:
+ case S_CALLSITEINFO:
+ case S_HEAPALLOCSITE:
+ case S_LDATA32:
+ case S_GDATA32:
+ case S_LMANDATA:
+ case S_GMANDATA:
+ case S_LTHREAD32:
+ case S_GTHREAD32:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool lldb_private::npdb::SymbolIsCode(const CVSymbol &sym) {
+ switch (sym.kind()) {
+ case S_GPROC32:
+ case S_LPROC32:
+ case S_GPROC32_ID:
+ case S_LPROC32_ID:
+ case S_LPROC32_DPC:
+ case S_LPROC32_DPC_ID:
+ case S_THUNK32:
+ case S_TRAMPOLINE:
+ case S_COFFGROUP:
+ case S_BLOCK32:
+ return true;
+ default:
+ return false;
+ }
+}
+
+template <typename RecordT> RecordT createRecord(const CVSymbol &sym) {
+ RecordT record(static_cast<SymbolRecordKind>(sym.kind()));
+ cantFail(SymbolDeserializer::deserializeAs<RecordT>(sym, record));
+ return record;
+}
+
+template <typename RecordT>
+static SegmentOffset GetSegmentAndOffset(const CVSymbol &sym) {
+ RecordT record = createRecord<RecordT>(sym);
+ return {record.Segment, record.CodeOffset};
+}
+
+template <>
+SegmentOffset GetSegmentAndOffset<TrampolineSym>(const CVSymbol &sym) {
+ TrampolineSym record = createRecord<TrampolineSym>(sym);
+ return {record.ThunkSection, record.ThunkOffset};
+}
+
+template <> SegmentOffset GetSegmentAndOffset<Thunk32Sym>(const CVSymbol &sym) {
+ Thunk32Sym record = createRecord<Thunk32Sym>(sym);
+ return {record.Segment, record.Offset};
+}
+
+template <>
+SegmentOffset GetSegmentAndOffset<CoffGroupSym>(const CVSymbol &sym) {
+ CoffGroupSym record = createRecord<CoffGroupSym>(sym);
+ return {record.Segment, record.Offset};
+}
+
+template <> SegmentOffset GetSegmentAndOffset<DataSym>(const CVSymbol &sym) {
+ DataSym record = createRecord<DataSym>(sym);
+ return {record.Segment, record.DataOffset};
+}
+
+template <>
+SegmentOffset GetSegmentAndOffset<ThreadLocalDataSym>(const CVSymbol &sym) {
+ ThreadLocalDataSym record = createRecord<ThreadLocalDataSym>(sym);
+ return {record.Segment, record.DataOffset};
+}
+
+SegmentOffset lldb_private::npdb::GetSegmentAndOffset(const CVSymbol &sym) {
+ switch (sym.kind()) {
+ case S_GPROC32:
+ case S_LPROC32:
+ case S_GPROC32_ID:
+ case S_LPROC32_ID:
+ case S_LPROC32_DPC:
+ case S_LPROC32_DPC_ID:
+ return ::GetSegmentAndOffset<ProcSym>(sym);
+ case S_THUNK32:
+ return ::GetSegmentAndOffset<Thunk32Sym>(sym);
+ break;
+ case S_TRAMPOLINE:
+ return ::GetSegmentAndOffset<TrampolineSym>(sym);
+ break;
+ case S_COFFGROUP:
+ return ::GetSegmentAndOffset<CoffGroupSym>(sym);
+ break;
+ case S_BLOCK32:
+ return ::GetSegmentAndOffset<BlockSym>(sym);
+ break;
+ case S_LABEL32:
+ return ::GetSegmentAndOffset<LabelSym>(sym);
+ break;
+ case S_CALLSITEINFO:
+ return ::GetSegmentAndOffset<CallSiteInfoSym>(sym);
+ break;
+ case S_HEAPALLOCSITE:
+ return ::GetSegmentAndOffset<HeapAllocationSiteSym>(sym);
+ break;
+ case S_LDATA32:
+ case S_GDATA32:
+ case S_LMANDATA:
+ case S_GMANDATA:
+ return ::GetSegmentAndOffset<DataSym>(sym);
+ break;
+ case S_LTHREAD32:
+ case S_GTHREAD32:
+ return ::GetSegmentAndOffset<ThreadLocalDataSym>(sym);
+ break;
+ default:
+ lldbassert(false && "Record does not have a segment/offset!");
+ }
+ return {0, 0};
+}
+
+template <typename RecordT>
+SegmentOffsetLength GetSegmentOffsetAndLength(const CVSymbol &sym) {
+ RecordT record = createRecord<RecordT>(sym);
+ return {record.Segment, record.CodeOffset, record.CodeSize};
+}
+
+template <>
+SegmentOffsetLength
+GetSegmentOffsetAndLength<TrampolineSym>(const CVSymbol &sym) {
+ TrampolineSym record = createRecord<TrampolineSym>(sym);
+ return {record.ThunkSection, record.ThunkOffset, record.Size};
+}
+
+template <>
+SegmentOffsetLength GetSegmentOffsetAndLength<Thunk32Sym>(const CVSymbol &sym) {
+ Thunk32Sym record = createRecord<Thunk32Sym>(sym);
+ return SegmentOffsetLength{record.Segment, record.Offset, record.Length};
+}
+
+template <>
+SegmentOffsetLength
+GetSegmentOffsetAndLength<CoffGroupSym>(const CVSymbol &sym) {
+ CoffGroupSym record = createRecord<CoffGroupSym>(sym);
+ return SegmentOffsetLength{record.Segment, record.Offset, record.Size};
+}
+
+SegmentOffsetLength
+lldb_private::npdb::GetSegmentOffsetAndLength(const CVSymbol &sym) {
+ switch (sym.kind()) {
+ case S_GPROC32:
+ case S_LPROC32:
+ case S_GPROC32_ID:
+ case S_LPROC32_ID:
+ case S_LPROC32_DPC:
+ case S_LPROC32_DPC_ID:
+ return ::GetSegmentOffsetAndLength<ProcSym>(sym);
+ case S_THUNK32:
+ return ::GetSegmentOffsetAndLength<Thunk32Sym>(sym);
+ break;
+ case S_TRAMPOLINE:
+ return ::GetSegmentOffsetAndLength<TrampolineSym>(sym);
+ break;
+ case S_COFFGROUP:
+ return ::GetSegmentOffsetAndLength<CoffGroupSym>(sym);
+ break;
+ case S_BLOCK32:
+ return ::GetSegmentOffsetAndLength<BlockSym>(sym);
+ break;
+ default:
+ lldbassert(false && "Record does not have a segment/offset/length triple!");
+ }
+ return {0, 0, 0};
+}
+
+bool lldb_private::npdb::IsForwardRefUdt(CVType cvt) {
+ ClassRecord cr;
+ UnionRecord ur;
+ EnumRecord er;
+ switch (cvt.kind()) {
+ case LF_CLASS:
+ case LF_STRUCTURE:
+ case LF_INTERFACE:
+ llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, cr));
+ return cr.isForwardRef();
+ case LF_UNION:
+ llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, ur));
+ return ur.isForwardRef();
+ case LF_ENUM:
+ llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));
+ return er.isForwardRef();
+ default:
+ return false;
+ }
+}
+
+bool lldb_private::npdb::IsTagRecord(llvm::codeview::CVType cvt) {
+ switch (cvt.kind()) {
+ case LF_CLASS:
+ case LF_STRUCTURE:
+ case LF_UNION:
+ case LF_ENUM:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool lldb_private::npdb::IsClassStructUnion(llvm::codeview::CVType cvt) {
+ switch (cvt.kind()) {
+ case LF_CLASS:
+ case LF_STRUCTURE:
+ case LF_UNION:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool lldb_private::npdb::IsForwardRefUdt(const PdbTypeSymId &id,
+ TpiStream &tpi) {
+ if (id.is_ipi || id.index.isSimple())
+ return false;
+ return IsForwardRefUdt(tpi.getType(id.index));
+}
+
+bool lldb_private::npdb::IsTagRecord(const PdbTypeSymId &id, TpiStream &tpi) {
+ if (id.is_ipi || id.index.isSimple())
+ return false;
+ return IsTagRecord(tpi.getType(id.index));
+}
+
+lldb::AccessType
+lldb_private::npdb::TranslateMemberAccess(MemberAccess access) {
+ switch (access) {
+ case MemberAccess::Private:
+ return lldb::eAccessPrivate;
+ case MemberAccess::Protected:
+ return lldb::eAccessProtected;
+ case MemberAccess::Public:
+ return lldb::eAccessPublic;
+ case MemberAccess::None:
+ return lldb::eAccessNone;
+ }
+ llvm_unreachable("unreachable");
+}
+
+TypeIndex lldb_private::npdb::GetFieldListIndex(CVType cvt) {
+ switch (cvt.kind()) {
+ case LF_CLASS:
+ case LF_STRUCTURE:
+ case LF_INTERFACE: {
+ ClassRecord cr;
+ cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, cr));
+ return cr.FieldList;
+ }
+ case LF_UNION: {
+ UnionRecord ur;
+ cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, ur));
+ return ur.FieldList;
+ }
+ case LF_ENUM: {
+ EnumRecord er;
+ cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));
+ return er.FieldList;
+ }
+ default:
+ llvm_unreachable("Unreachable!");
+ }
+}
+
+TypeIndex lldb_private::npdb::LookThroughModifierRecord(CVType modifier) {
+ lldbassert(modifier.kind() == LF_MODIFIER);
+ ModifierRecord mr;
+ llvm::cantFail(TypeDeserializer::deserializeAs<ModifierRecord>(modifier, mr));
+ return mr.ModifiedType;
+}
+
+llvm::StringRef lldb_private::npdb::DropNameScope(llvm::StringRef name) {
+ return MSVCUndecoratedNameParser::DropScope(name);
+}
+
+VariableInfo lldb_private::npdb::GetVariableNameInfo(CVSymbol sym) {
+ VariableInfo result = {};
+
+ if (sym.kind() == S_REGREL32) {
+ RegRelativeSym reg(SymbolRecordKind::RegRelativeSym);
+ cantFail(SymbolDeserializer::deserializeAs<RegRelativeSym>(sym, reg));
+ result.type = reg.Type;
+ result.name = reg.Name;
+ return result;
+ }
+
+ if (sym.kind() == S_REGISTER) {
+ RegisterSym reg(SymbolRecordKind::RegisterSym);
+ cantFail(SymbolDeserializer::deserializeAs<RegisterSym>(sym, reg));
+ result.type = reg.Index;
+ result.name = reg.Name;
+ return result;
+ }
+
+ if (sym.kind() == S_LOCAL) {
+ LocalSym local(SymbolRecordKind::LocalSym);
+ cantFail(SymbolDeserializer::deserializeAs<LocalSym>(sym, local));
+ result.type = local.Type;
+ result.name = local.Name;
+ result.is_param =
+ ((local.Flags & LocalSymFlags::IsParameter) != LocalSymFlags::None);
+ return result;
+ }
+
+ if (sym.kind() == S_GDATA32 || sym.kind() == S_LDATA32) {
+ DataSym data(SymbolRecordKind::DataSym);
+ cantFail(SymbolDeserializer::deserializeAs<DataSym>(sym, data));
+ result.type = data.Type;
+ result.name = data.Name;
+ return result;
+ }
+
+ if (sym.kind() == S_GTHREAD32 || sym.kind() == S_LTHREAD32) {
+ ThreadLocalDataSym data(SymbolRecordKind::ThreadLocalDataSym);
+ cantFail(SymbolDeserializer::deserializeAs<ThreadLocalDataSym>(sym, data));
+ result.type = data.Type;
+ result.name = data.Name;
+ return result;
+ }
+
+ if (sym.kind() == S_CONSTANT) {
+ ConstantSym constant(SymbolRecordKind::ConstantSym);
+ cantFail(SymbolDeserializer::deserializeAs<ConstantSym>(sym, constant));
+ result.type = constant.Type;
+ result.name = constant.Name;
+ return result;
+ }
+
+ lldbassert(false && "Invalid variable record kind!");
+ return {};
+}
+
+static llvm::FixedStreamArray<FrameData>::Iterator
+GetCorrespondingFrameData(lldb::addr_t load_addr,
+ const DebugFrameDataSubsectionRef &fpo_data,
+ const Variable::RangeList &ranges) {
+ lldbassert(!ranges.IsEmpty());
+
+ // assume that all variable ranges correspond to one frame data
+ using RangeListEntry = Variable::RangeList::Entry;
+ const RangeListEntry &range = ranges.GetEntryRef(0);
+
+ auto it = fpo_data.begin();
+
+ // start by searching first frame data range containing variable range
+ for (; it != fpo_data.end(); ++it) {
+ RangeListEntry fd_range(load_addr + it->RvaStart, it->CodeSize);
+
+ if (fd_range.Contains(range)) {
+ break;
+ }
+ }
+
+ // then first most nested entry that still contains variable range
+ auto found = it;
+ for (; it != fpo_data.end(); ++it) {
+ RangeListEntry fd_range(load_addr + it->RvaStart, it->CodeSize);
+
+ if (!fd_range.Contains(range)) {
+ break;
+ }
+ found = it;
+ }
+
+ return found;
+}
+
+static bool GetFrameDataProgram(PdbIndex &index,
+ const Variable::RangeList &ranges,
+ llvm::StringRef &out_program) {
+ const DebugFrameDataSubsectionRef &new_fpo_data =
+ index.dbi().getNewFpoRecords();
+
+ auto frame_data_it =
+ GetCorrespondingFrameData(index.GetLoadAddress(), new_fpo_data, ranges);
+ if (frame_data_it == new_fpo_data.end())
+ return false;
+
+ auto strings = index.pdb().getStringTable();
+ if (!strings) {
+ consumeError(strings.takeError());
+ return false;
+ }
+ out_program = cantFail(strings->getStringForID(frame_data_it->FrameFunc));
+ return true;
+}
+
+static RegisterId GetBaseFrameRegister(PdbIndex &index,
+ PdbCompilandSymId frame_proc_id,
+ bool is_parameter) {
+ CVSymbol frame_proc_cvs = index.ReadSymbolRecord(frame_proc_id);
+ if (frame_proc_cvs.kind() != S_FRAMEPROC)
+ return RegisterId::NONE;
+
+ FrameProcSym frame_proc(SymbolRecordKind::FrameProcSym);
+ cantFail(SymbolDeserializer::deserializeAs<FrameProcSym>(frame_proc_cvs,
+ frame_proc));
+
+ CPUType cpu_type = index.compilands()
+ .GetCompiland(frame_proc_id.modi)
+ ->m_compile_opts->Machine;
+
+ return is_parameter ? frame_proc.getParamFramePtrReg(cpu_type)
+ : frame_proc.getLocalFramePtrReg(cpu_type);
+}
+
+VariableInfo lldb_private::npdb::GetVariableLocationInfo(
+ PdbIndex &index, PdbCompilandSymId var_id, Block &func_block,
+ lldb::ModuleSP module) {
+
+ CVSymbol sym = index.ReadSymbolRecord(var_id);
+
+ VariableInfo result = GetVariableNameInfo(sym);
+
+ if (sym.kind() == S_REGREL32) {
+ RegRelativeSym reg(SymbolRecordKind::RegRelativeSym);
+ cantFail(SymbolDeserializer::deserializeAs<RegRelativeSym>(sym, reg));
+ result.location = DWARFExpressionList(
+ module, MakeRegRelLocationExpression(reg.Register, reg.Offset, module),
+ nullptr);
+ return result;
+ }
+
+ if (sym.kind() == S_REGISTER) {
+ RegisterSym reg(SymbolRecordKind::RegisterSym);
+ cantFail(SymbolDeserializer::deserializeAs<RegisterSym>(sym, reg));
+ result.location = DWARFExpressionList(
+ module, MakeEnregisteredLocationExpression(reg.Register, module),
+ nullptr);
+ return result;
+ }
+
+ if (sym.kind() == S_LOCAL) {
+ LocalSym local(SymbolRecordKind::LocalSym);
+ if (llvm::Error error =
+ SymbolDeserializer::deserializeAs<LocalSym>(sym, local)) {
+ llvm::consumeError(std::move(error));
+ return result;
+ }
+
+ PdbCompilandSymId loc_specifier_id(var_id.modi,
+ var_id.offset + sym.RecordData.size());
+ CVSymbol loc_specifier_cvs;
+ // Only used for S_DEFRANGE_FRAMEPOINTER_REL.
+ RegisterId base_reg = RegisterId::NONE;
+ size_t type_size = GetSizeOfType(result.type, index.tpi());
+ // A map from offset of a field in parent to size of the field.
+ std::map<uint64_t, size_t> offset_to_size;
+
+ // When overlaps happens, always prefer the one that doesn't split the value
+ // into multiple locations and the location parsed first is perfered.
+ RangeMap location_map;
+
+ // Iterate through all location records after S_LOCAL. They describe the
+ // value of this variable at different locations.
+ bool finished = false;
+ while (!finished) {
+ loc_specifier_cvs = index.ReadSymbolRecord(loc_specifier_id);
+ switch (loc_specifier_cvs.kind()) {
+ case S_DEFRANGE_FRAMEPOINTER_REL: {
+ DefRangeFramePointerRelSym loc(
+ SymbolRecordKind::DefRangeFramePointerRelSym);
+ if (llvm::Error error =
+ SymbolDeserializer::deserializeAs<DefRangeFramePointerRelSym>(
+ loc_specifier_cvs, loc)) {
+ llvm::consumeError(std::move(error));
+ return result;
+ }
+ Variable::RangeList raw_ranges =
+ MakeRangeList(index, loc.Range, loc.Gaps);
+ if (base_reg == RegisterId::NONE) {
+ PdbCompilandSymId func_scope_id =
+ PdbSymUid(func_block.GetID()).asCompilandSym();
+ CVSymbol func_block_cvs = index.ReadSymbolRecord(func_scope_id);
+ lldbassert(func_block_cvs.kind() == S_GPROC32 ||
+ func_block_cvs.kind() == S_LPROC32);
+ PdbCompilandSymId frame_proc_id(func_scope_id.modi,
+ func_scope_id.offset +
+ func_block_cvs.length());
+ base_reg =
+ GetBaseFrameRegister(index, frame_proc_id, result.is_param);
+ if (base_reg == RegisterId::NONE)
+ break;
+ }
+ DWARFExpression expr;
+ if (base_reg == RegisterId::VFRAME) {
+ llvm::StringRef program;
+ if (GetFrameDataProgram(index, raw_ranges, program))
+ expr = MakeVFrameRelLocationExpression(program, loc.Hdr.Offset,
+ module);
+ else {
+ // invalid variable
+ }
+ } else
+ expr = MakeRegRelLocationExpression(base_reg, loc.Hdr.Offset, module);
+ AddDwarfRange(location_map, expr, raw_ranges);
+ break;
+ }
+ case S_DEFRANGE_REGISTER: {
+ DefRangeRegisterSym loc(SymbolRecordKind::DefRangeRegisterSym);
+ if (llvm::Error error =
+ SymbolDeserializer::deserializeAs<DefRangeRegisterSym>(
+ loc_specifier_cvs, loc)) {
+ llvm::consumeError(std::move(error));
+ return result;
+ }
+ RegisterId reg_id = (RegisterId)(uint16_t)loc.Hdr.Register;
+ Variable::RangeList raw_ranges =
+ MakeRangeList(index, loc.Range, loc.Gaps);
+ DWARFExpression expr =
+ MakeEnregisteredLocationExpression(reg_id, module);
+ AddDwarfRange(location_map, expr, raw_ranges);
+ break;
+ }
+ case S_DEFRANGE_REGISTER_REL: {
+ DefRangeRegisterRelSym loc(SymbolRecordKind::DefRangeRegisterRelSym);
+ if (llvm::Error error =
+ SymbolDeserializer::deserializeAs<DefRangeRegisterRelSym>(
+ loc_specifier_cvs, loc)) {
+ llvm::consumeError(std::move(error));
+ return result;
+ }
+ Variable::RangeList raw_ranges =
+ MakeRangeList(index, loc.Range, loc.Gaps);
+ RegisterId reg_id = (RegisterId)(uint16_t)loc.Hdr.Register;
+ DWARFExpression expr;
+ if (reg_id == RegisterId::VFRAME) {
+ llvm::StringRef program;
+ if (GetFrameDataProgram(index, raw_ranges, program))
+ expr = MakeVFrameRelLocationExpression(
+ program, loc.Hdr.BasePointerOffset, module);
+ else {
+ // invalid variable
+ }
+ } else {
+ expr = MakeRegRelLocationExpression(reg_id, loc.Hdr.BasePointerOffset,
+ module);
+ }
+ // FIXME: If it's UDT, we need to know the size of the value in byte.
+ if (!loc.hasSpilledUDTMember())
+ AddDwarfRange(location_map, expr, raw_ranges);
+ break;
+ }
+ case S_DEFRANGE_SUBFIELD_REGISTER: {
+ DefRangeSubfieldRegisterSym loc(
+ SymbolRecordKind::DefRangeSubfieldRegisterSym);
+ if (llvm::Error error =
+ SymbolDeserializer::deserializeAs<DefRangeSubfieldRegisterSym>(
+ loc_specifier_cvs, loc)) {
+ llvm::consumeError(std::move(error));
+ return result;
+ }
+
+ Variable::RangeList ranges = MakeRangeList(index, loc.Range, loc.Gaps);
+ uint32_t reg_size =
+ GetRegisterSize((RegisterId)(uint16_t)loc.Hdr.Register);
+ if (reg_size == 0)
+ break;
+ offset_to_size[loc.Hdr.OffsetInParent] = reg_size;
+ AddMemberLocationRanges(location_map, loc.Hdr.OffsetInParent,
+ {loc.Hdr.Register, 0, true}, ranges);
+ break;
+ }
+ // FIXME: Handle other kinds. LLVM only generates the 4 types of records
+ // above. MSVC generates other location types.
+ case S_DEFRANGE:
+ case S_DEFRANGE_SUBFIELD:
+ case S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE:
+ break;
+ default:
+ finished = true;
+ break;
+ }
+ loc_specifier_id = PdbCompilandSymId(
+ loc_specifier_id.modi,
+ loc_specifier_id.offset + loc_specifier_cvs.RecordData.size());
+ }
+ for (const auto &entry : location_map) {
+ DWARFExpression dwarf_expr =
+ entry.data.is_dwarf ? entry.data.expr
+ : MakeEnregisteredLocationExpressionForComposite(
+ entry.data.offset_to_location,
+ offset_to_size, type_size, module);
+
+ result.location.AddExpression(entry.GetRangeBase(), entry.GetRangeEnd(),
+ dwarf_expr);
+ }
+ return result;
+ }
+ llvm_unreachable("Symbol is not a local variable!");
+ return result;
+}
+
+lldb::BasicType
+lldb_private::npdb::GetCompilerTypeForSimpleKind(SimpleTypeKind kind) {
+ switch (kind) {
+ case SimpleTypeKind::Boolean128:
+ case SimpleTypeKind::Boolean16:
+ case SimpleTypeKind::Boolean32:
+ case SimpleTypeKind::Boolean64:
+ case SimpleTypeKind::Boolean8:
+ return lldb::eBasicTypeBool;
+ case SimpleTypeKind::Byte:
+ case SimpleTypeKind::UnsignedCharacter:
+ return lldb::eBasicTypeUnsignedChar;
+ case SimpleTypeKind::NarrowCharacter:
+ return lldb::eBasicTypeChar;
+ case SimpleTypeKind::SignedCharacter:
+ case SimpleTypeKind::SByte:
+ return lldb::eBasicTypeSignedChar;
+ case SimpleTypeKind::Character16:
+ return lldb::eBasicTypeChar16;
+ case SimpleTypeKind::Character32:
+ return lldb::eBasicTypeChar32;
+ case SimpleTypeKind::Character8:
+ return lldb::eBasicTypeChar8;
+ case SimpleTypeKind::Complex80:
+ return lldb::eBasicTypeLongDoubleComplex;
+ case SimpleTypeKind::Complex64:
+ return lldb::eBasicTypeDoubleComplex;
+ case SimpleTypeKind::Complex32:
+ return lldb::eBasicTypeFloatComplex;
+ case SimpleTypeKind::Float128:
+ case SimpleTypeKind::Float80:
+ return lldb::eBasicTypeLongDouble;
+ case SimpleTypeKind::Float64:
+ return lldb::eBasicTypeDouble;
+ case SimpleTypeKind::Float32:
+ return lldb::eBasicTypeFloat;
+ case SimpleTypeKind::Float16:
+ return lldb::eBasicTypeHalf;
+ case SimpleTypeKind::Int128:
+ return lldb::eBasicTypeInt128;
+ case SimpleTypeKind::Int64:
+ case SimpleTypeKind::Int64Quad:
+ return lldb::eBasicTypeLongLong;
+ case SimpleTypeKind::Int32:
+ return lldb::eBasicTypeInt;
+ case SimpleTypeKind::Int16:
+ case SimpleTypeKind::Int16Short:
+ return lldb::eBasicTypeShort;
+ case SimpleTypeKind::UInt128:
+ return lldb::eBasicTypeUnsignedInt128;
+ case SimpleTypeKind::UInt64:
+ case SimpleTypeKind::UInt64Quad:
+ return lldb::eBasicTypeUnsignedLongLong;
+ case SimpleTypeKind::HResult:
+ case SimpleTypeKind::UInt32:
+ return lldb::eBasicTypeUnsignedInt;
+ case SimpleTypeKind::UInt16:
+ case SimpleTypeKind::UInt16Short:
+ return lldb::eBasicTypeUnsignedShort;
+ case SimpleTypeKind::Int32Long:
+ return lldb::eBasicTypeLong;
+ case SimpleTypeKind::UInt32Long:
+ return lldb::eBasicTypeUnsignedLong;
+ case SimpleTypeKind::Void:
+ return lldb::eBasicTypeVoid;
+ case SimpleTypeKind::WideCharacter:
+ return lldb::eBasicTypeWChar;
+ default:
+ return lldb::eBasicTypeInvalid;
+ }
+}
+
+size_t lldb_private::npdb::GetTypeSizeForSimpleKind(SimpleTypeKind kind) {
+ switch (kind) {
+ case SimpleTypeKind::Boolean128:
+ case SimpleTypeKind::Int128:
+ case SimpleTypeKind::UInt128:
+ case SimpleTypeKind::Float128:
+ return 16;
+ case SimpleTypeKind::Complex80:
+ case SimpleTypeKind::Float80:
+ return 10;
+ case SimpleTypeKind::Boolean64:
+ case SimpleTypeKind::Complex64:
+ case SimpleTypeKind::UInt64:
+ case SimpleTypeKind::UInt64Quad:
+ case SimpleTypeKind::Float64:
+ case SimpleTypeKind::Int64:
+ case SimpleTypeKind::Int64Quad:
+ return 8;
+ case SimpleTypeKind::Boolean32:
+ case SimpleTypeKind::Character32:
+ case SimpleTypeKind::Complex32:
+ case SimpleTypeKind::Float32:
+ case SimpleTypeKind::Int32:
+ case SimpleTypeKind::Int32Long:
+ case SimpleTypeKind::UInt32Long:
+ case SimpleTypeKind::HResult:
+ case SimpleTypeKind::UInt32:
+ return 4;
+ case SimpleTypeKind::Boolean16:
+ case SimpleTypeKind::Character16:
+ case SimpleTypeKind::Float16:
+ case SimpleTypeKind::Int16:
+ case SimpleTypeKind::Int16Short:
+ case SimpleTypeKind::UInt16:
+ case SimpleTypeKind::UInt16Short:
+ case SimpleTypeKind::WideCharacter:
+ return 2;
+ case SimpleTypeKind::Boolean8:
+ case SimpleTypeKind::Byte:
+ case SimpleTypeKind::UnsignedCharacter:
+ case SimpleTypeKind::NarrowCharacter:
+ case SimpleTypeKind::SignedCharacter:
+ case SimpleTypeKind::SByte:
+ case SimpleTypeKind::Character8:
+ return 1;
+ case SimpleTypeKind::Void:
+ default:
+ return 0;
+ }
+}
+
+PdbTypeSymId lldb_private::npdb::GetBestPossibleDecl(PdbTypeSymId id,
+ TpiStream &tpi) {
+ if (id.index.isSimple())
+ return id;
+
+ CVType cvt = tpi.getType(id.index);
+
+ // Only tag records have a best and a worst record.
+ if (!IsTagRecord(cvt))
+ return id;
+
+ // Tag records that are not forward decls are full decls, hence they are the
+ // best.
+ if (!IsForwardRefUdt(cvt))
+ return id;
+
+ return llvm::cantFail(tpi.findFullDeclForForwardRef(id.index));
+}
+
+template <typename RecordType> static size_t GetSizeOfTypeInternal(CVType cvt) {
+ RecordType record;
+ llvm::cantFail(TypeDeserializer::deserializeAs<RecordType>(cvt, record));
+ return record.getSize();
+}
+
+size_t lldb_private::npdb::GetSizeOfType(PdbTypeSymId id,
+ llvm::pdb::TpiStream &tpi) {
+ if (id.index.isSimple()) {
+ switch (id.index.getSimpleMode()) {
+ case SimpleTypeMode::Direct:
+ return GetTypeSizeForSimpleKind(id.index.getSimpleKind());
+ case SimpleTypeMode::NearPointer32:
+ case SimpleTypeMode::FarPointer32:
+ return 4;
+ case SimpleTypeMode::NearPointer64:
+ return 8;
+ case SimpleTypeMode::NearPointer128:
+ return 16;
+ default:
+ break;
+ }
+ return 0;
+ }
+
+ TypeIndex index = id.index;
+ if (IsForwardRefUdt(index, tpi))
+ index = llvm::cantFail(tpi.findFullDeclForForwardRef(index));
+
+ CVType cvt = tpi.getType(index);
+ switch (cvt.kind()) {
+ case LF_MODIFIER:
+ return GetSizeOfType({LookThroughModifierRecord(cvt)}, tpi);
+ case LF_ENUM: {
+ EnumRecord record;
+ llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, record));
+ return GetSizeOfType({record.UnderlyingType}, tpi);
+ }
+ case LF_POINTER:
+ return GetSizeOfTypeInternal<PointerRecord>(cvt);
+ case LF_ARRAY:
+ return GetSizeOfTypeInternal<ArrayRecord>(cvt);
+ case LF_CLASS:
+ case LF_STRUCTURE:
+ case LF_INTERFACE:
+ return GetSizeOfTypeInternal<ClassRecord>(cvt);
+ case LF_UNION:
+ return GetSizeOfTypeInternal<UnionRecord>(cvt);
+ case LF_BITFIELD: {
+ BitFieldRecord record;
+ llvm::cantFail(TypeDeserializer::deserializeAs<BitFieldRecord>(cvt, record));
+ return GetSizeOfType({record.Type}, tpi);
+ }
+ default:
+ break;
+ }
+ return 0;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h
new file mode 100644
index 000000000000..1f888f4de1fe
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h
@@ -0,0 +1,157 @@
+//===-- PdbUtil.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_NATIVEPDB_PDBUTIL_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBUTIL_H
+
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/lldb-enumerations.h"
+
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/PDB/PDBTypes.h"
+
+#include "PdbSymUid.h"
+
+#include <tuple>
+#include <utility>
+
+namespace llvm {
+namespace pdb {
+class TpiStream;
+}
+} // namespace llvm
+
+namespace lldb_private {
+namespace npdb {
+
+class PdbIndex;
+
+struct CVTagRecord {
+ enum Kind { Class, Struct, Union, Enum };
+
+ static CVTagRecord create(llvm::codeview::CVType type);
+
+ Kind kind() const { return m_kind; }
+
+ const llvm::codeview::TagRecord &asTag() const {
+ if (m_kind == Struct || m_kind == Class)
+ return cvclass;
+ if (m_kind == Enum)
+ return cvenum;
+ return cvunion;
+ }
+
+ const llvm::codeview::ClassRecord &asClass() const {
+ assert(m_kind == Struct || m_kind == Class);
+ return cvclass;
+ }
+
+ const llvm::codeview::EnumRecord &asEnum() const {
+ assert(m_kind == Enum);
+ return cvenum;
+ }
+
+ const llvm::codeview::UnionRecord &asUnion() const {
+ assert(m_kind == Union);
+ return cvunion;
+ }
+
+ llvm::StringRef name() const {
+ if (m_kind == Struct || m_kind == Union)
+ return cvclass.Name;
+ if (m_kind == Enum)
+ return cvenum.Name;
+ return cvunion.Name;
+ }
+
+private:
+ CVTagRecord(llvm::codeview::ClassRecord &&c);
+ CVTagRecord(llvm::codeview::UnionRecord &&u);
+ CVTagRecord(llvm::codeview::EnumRecord &&e);
+ union {
+ llvm::codeview::ClassRecord cvclass;
+ llvm::codeview::EnumRecord cvenum;
+ llvm::codeview::UnionRecord cvunion;
+ };
+ Kind m_kind;
+};
+
+struct SegmentOffset {
+ SegmentOffset() = default;
+ SegmentOffset(uint16_t s, uint32_t o) : segment(s), offset(o) {}
+ uint16_t segment = 0;
+ uint32_t offset = 0;
+};
+
+struct SegmentOffsetLength {
+ SegmentOffsetLength() = default;
+ SegmentOffsetLength(uint16_t s, uint32_t o, uint32_t l)
+ : so(s, o), length(l) {}
+ SegmentOffset so;
+ uint32_t length = 0;
+};
+
+struct VariableInfo {
+ llvm::StringRef name;
+ llvm::codeview::TypeIndex type;
+ DWARFExpressionList location;
+ bool is_param;
+};
+
+llvm::pdb::PDB_SymType CVSymToPDBSym(llvm::codeview::SymbolKind kind);
+llvm::pdb::PDB_SymType CVTypeToPDBType(llvm::codeview::TypeLeafKind kind);
+
+bool SymbolHasAddress(const llvm::codeview::CVSymbol &sym);
+bool SymbolIsCode(const llvm::codeview::CVSymbol &sym);
+
+SegmentOffset GetSegmentAndOffset(const llvm::codeview::CVSymbol &sym);
+SegmentOffsetLength
+GetSegmentOffsetAndLength(const llvm::codeview::CVSymbol &sym);
+
+template <typename RecordT> bool IsValidRecord(const RecordT &sym) {
+ return true;
+}
+
+inline bool IsValidRecord(const llvm::codeview::ProcRefSym &sym) {
+ // S_PROCREF symbols have 1-based module indices.
+ return sym.Module > 0;
+}
+
+bool IsForwardRefUdt(llvm::codeview::CVType cvt);
+bool IsTagRecord(llvm::codeview::CVType cvt);
+bool IsClassStructUnion(llvm::codeview::CVType cvt);
+
+bool IsForwardRefUdt(const PdbTypeSymId &id, llvm::pdb::TpiStream &tpi);
+bool IsTagRecord(const PdbTypeSymId &id, llvm::pdb::TpiStream &tpi);
+
+lldb::AccessType TranslateMemberAccess(llvm::codeview::MemberAccess access);
+llvm::codeview::TypeIndex GetFieldListIndex(llvm::codeview::CVType cvt);
+llvm::codeview::TypeIndex
+LookThroughModifierRecord(llvm::codeview::CVType modifier);
+
+llvm::StringRef DropNameScope(llvm::StringRef name);
+
+VariableInfo GetVariableNameInfo(llvm::codeview::CVSymbol symbol);
+VariableInfo GetVariableLocationInfo(PdbIndex &index, PdbCompilandSymId var_id,
+ Block &func_block, lldb::ModuleSP module);
+
+size_t GetTypeSizeForSimpleKind(llvm::codeview::SimpleTypeKind kind);
+lldb::BasicType
+GetCompilerTypeForSimpleKind(llvm::codeview::SimpleTypeKind kind);
+
+PdbTypeSymId GetBestPossibleDecl(PdbTypeSymId id, llvm::pdb::TpiStream &tpi);
+
+size_t GetSizeOfType(PdbTypeSymId id, llvm::pdb::TpiStream &tpi);
+
+} // namespace npdb
+} // namespace lldb_private
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
new file mode 100644
index 000000000000..7fded6a31a3a
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -0,0 +1,2336 @@
+//===-- SymbolFileNativePDB.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 "SymbolFileNativePDB.h"
+
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
+#include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h"
+#include "Plugins/ObjectFile/PDB/ObjectFilePDB.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/LineTable.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+
+#include "llvm/DebugInfo/CodeView/CVRecord.h"
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/DebugInfo/CodeView/RecordName.h"
+#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecordHelpers.h"
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
+#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/DebugInfo/PDB/PDB.h"
+#include "llvm/DebugInfo/PDB/PDBTypes.h"
+#include "llvm/Demangle/MicrosoftDemangle.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+#include "DWARFLocationExpression.h"
+#include "PdbSymUid.h"
+#include "PdbUtil.h"
+#include "UdtRecordCompleter.h"
+#include <optional>
+#include <string_view>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace npdb;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+char SymbolFileNativePDB::ID;
+
+static lldb::LanguageType TranslateLanguage(PDB_Lang lang) {
+ switch (lang) {
+ case PDB_Lang::Cpp:
+ return lldb::LanguageType::eLanguageTypeC_plus_plus;
+ case PDB_Lang::C:
+ return lldb::LanguageType::eLanguageTypeC;
+ case PDB_Lang::Swift:
+ return lldb::LanguageType::eLanguageTypeSwift;
+ case PDB_Lang::Rust:
+ return lldb::LanguageType::eLanguageTypeRust;
+ case PDB_Lang::ObjC:
+ return lldb::LanguageType::eLanguageTypeObjC;
+ case PDB_Lang::ObjCpp:
+ return lldb::LanguageType::eLanguageTypeObjC_plus_plus;
+ default:
+ return lldb::LanguageType::eLanguageTypeUnknown;
+ }
+}
+
+static std::unique_ptr<PDBFile>
+loadMatchingPDBFile(std::string exe_path, llvm::BumpPtrAllocator &allocator) {
+ // Try to find a matching PDB for an EXE.
+ using namespace llvm::object;
+ auto expected_binary = createBinary(exe_path);
+
+ // If the file isn't a PE/COFF executable, fail.
+ if (!expected_binary) {
+ llvm::consumeError(expected_binary.takeError());
+ return nullptr;
+ }
+ OwningBinary<Binary> binary = std::move(*expected_binary);
+
+ // TODO: Avoid opening the PE/COFF binary twice by reading this information
+ // directly from the lldb_private::ObjectFile.
+ auto *obj = llvm::dyn_cast<llvm::object::COFFObjectFile>(binary.getBinary());
+ if (!obj)
+ return nullptr;
+ const llvm::codeview::DebugInfo *pdb_info = nullptr;
+
+ // If it doesn't have a debug directory, fail.
+ llvm::StringRef pdb_file;
+ if (llvm::Error e = obj->getDebugPDBInfo(pdb_info, pdb_file)) {
+ consumeError(std::move(e));
+ return nullptr;
+ }
+
+ // If the file doesn't exist, perhaps the path specified at build time
+ // doesn't match the PDB's current location, so check the location of the
+ // executable.
+ if (!FileSystem::Instance().Exists(pdb_file)) {
+ const auto exe_dir = FileSpec(exe_path).CopyByRemovingLastPathComponent();
+ const auto pdb_name = FileSpec(pdb_file).GetFilename().GetCString();
+ pdb_file = exe_dir.CopyByAppendingPathComponent(pdb_name).GetPathAsConstString().GetStringRef();
+ }
+
+ // If the file is not a PDB or if it doesn't have a matching GUID, fail.
+ auto pdb = ObjectFilePDB::loadPDBFile(std::string(pdb_file), allocator);
+ if (!pdb)
+ return nullptr;
+
+ auto expected_info = pdb->getPDBInfoStream();
+ if (!expected_info) {
+ llvm::consumeError(expected_info.takeError());
+ return nullptr;
+ }
+ llvm::codeview::GUID guid;
+ memcpy(&guid, pdb_info->PDB70.Signature, 16);
+
+ if (expected_info->getGuid() != guid)
+ return nullptr;
+ return pdb;
+}
+
+static bool IsFunctionPrologue(const CompilandIndexItem &cci,
+ lldb::addr_t addr) {
+ // FIXME: Implement this.
+ return false;
+}
+
+static bool IsFunctionEpilogue(const CompilandIndexItem &cci,
+ lldb::addr_t addr) {
+ // FIXME: Implement this.
+ return false;
+}
+
+static llvm::StringRef GetSimpleTypeName(SimpleTypeKind kind) {
+ switch (kind) {
+ case SimpleTypeKind::Boolean128:
+ case SimpleTypeKind::Boolean16:
+ case SimpleTypeKind::Boolean32:
+ case SimpleTypeKind::Boolean64:
+ case SimpleTypeKind::Boolean8:
+ return "bool";
+ case SimpleTypeKind::Byte:
+ case SimpleTypeKind::UnsignedCharacter:
+ return "unsigned char";
+ case SimpleTypeKind::NarrowCharacter:
+ return "char";
+ case SimpleTypeKind::SignedCharacter:
+ case SimpleTypeKind::SByte:
+ return "signed char";
+ case SimpleTypeKind::Character16:
+ return "char16_t";
+ case SimpleTypeKind::Character32:
+ return "char32_t";
+ case SimpleTypeKind::Character8:
+ return "char8_t";
+ case SimpleTypeKind::Complex80:
+ case SimpleTypeKind::Complex64:
+ case SimpleTypeKind::Complex32:
+ return "complex";
+ case SimpleTypeKind::Float128:
+ case SimpleTypeKind::Float80:
+ return "long double";
+ case SimpleTypeKind::Float64:
+ return "double";
+ case SimpleTypeKind::Float32:
+ return "float";
+ case SimpleTypeKind::Float16:
+ return "single";
+ case SimpleTypeKind::Int128:
+ return "__int128";
+ case SimpleTypeKind::Int64:
+ case SimpleTypeKind::Int64Quad:
+ return "int64_t";
+ case SimpleTypeKind::Int32:
+ return "int";
+ case SimpleTypeKind::Int16:
+ return "short";
+ case SimpleTypeKind::UInt128:
+ return "unsigned __int128";
+ case SimpleTypeKind::UInt64:
+ case SimpleTypeKind::UInt64Quad:
+ return "uint64_t";
+ case SimpleTypeKind::HResult:
+ return "HRESULT";
+ case SimpleTypeKind::UInt32:
+ return "unsigned";
+ case SimpleTypeKind::UInt16:
+ case SimpleTypeKind::UInt16Short:
+ return "unsigned short";
+ case SimpleTypeKind::Int32Long:
+ return "long";
+ case SimpleTypeKind::UInt32Long:
+ return "unsigned long";
+ case SimpleTypeKind::Void:
+ return "void";
+ case SimpleTypeKind::WideCharacter:
+ return "wchar_t";
+ default:
+ return "";
+ }
+}
+
+static bool IsClassRecord(TypeLeafKind kind) {
+ switch (kind) {
+ case LF_STRUCTURE:
+ case LF_CLASS:
+ case LF_INTERFACE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static std::optional<CVTagRecord>
+GetNestedTagDefinition(const NestedTypeRecord &Record,
+ const CVTagRecord &parent, TpiStream &tpi) {
+ // An LF_NESTTYPE is essentially a nested typedef / using declaration, but it
+ // is also used to indicate the primary definition of a nested class. That is
+ // to say, if you have:
+ // struct A {
+ // struct B {};
+ // using C = B;
+ // };
+ // Then in the debug info, this will appear as:
+ // LF_STRUCTURE `A::B` [type index = N]
+ // LF_STRUCTURE `A`
+ // LF_NESTTYPE [name = `B`, index = N]
+ // LF_NESTTYPE [name = `C`, index = N]
+ // In order to accurately reconstruct the decl context hierarchy, we need to
+ // know which ones are actual definitions and which ones are just aliases.
+
+ // If it's a simple type, then this is something like `using foo = int`.
+ if (Record.Type.isSimple())
+ return std::nullopt;
+
+ CVType cvt = tpi.getType(Record.Type);
+
+ if (!IsTagRecord(cvt))
+ return std::nullopt;
+
+ // If it's an inner definition, then treat whatever name we have here as a
+ // single component of a mangled name. So we can inject it into the parent's
+ // mangled name to see if it matches.
+ CVTagRecord child = CVTagRecord::create(cvt);
+ std::string qname = std::string(parent.asTag().getUniqueName());
+ if (qname.size() < 4 || child.asTag().getUniqueName().size() < 4)
+ return std::nullopt;
+
+ // qname[3] is the tag type identifier (struct, class, union, etc). Since the
+ // inner tag type is not necessarily the same as the outer tag type, re-write
+ // it to match the inner tag type.
+ qname[3] = child.asTag().getUniqueName()[3];
+ std::string piece;
+ if (qname[3] == 'W')
+ piece = "4";
+ piece += Record.Name;
+ piece.push_back('@');
+ qname.insert(4, std::move(piece));
+ if (qname != child.asTag().UniqueName)
+ return std::nullopt;
+
+ return std::move(child);
+}
+
+void SymbolFileNativePDB::Initialize() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(), CreateInstance,
+ DebuggerInitialize);
+}
+
+void SymbolFileNativePDB::Terminate() {
+ PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+void SymbolFileNativePDB::DebuggerInitialize(Debugger &debugger) {}
+
+llvm::StringRef SymbolFileNativePDB::GetPluginDescriptionStatic() {
+ return "Microsoft PDB debug symbol cross-platform file reader.";
+}
+
+SymbolFile *SymbolFileNativePDB::CreateInstance(ObjectFileSP objfile_sp) {
+ return new SymbolFileNativePDB(std::move(objfile_sp));
+}
+
+SymbolFileNativePDB::SymbolFileNativePDB(ObjectFileSP objfile_sp)
+ : SymbolFileCommon(std::move(objfile_sp)) {}
+
+SymbolFileNativePDB::~SymbolFileNativePDB() = default;
+
+uint32_t SymbolFileNativePDB::CalculateAbilities() {
+ uint32_t abilities = 0;
+ if (!m_objfile_sp)
+ return 0;
+
+ if (!m_index) {
+ // Lazily load and match the PDB file, but only do this once.
+ PDBFile *pdb_file;
+ if (auto *pdb = llvm::dyn_cast<ObjectFilePDB>(m_objfile_sp.get())) {
+ pdb_file = &pdb->GetPDBFile();
+ } else {
+ m_file_up = loadMatchingPDBFile(m_objfile_sp->GetFileSpec().GetPath(),
+ m_allocator);
+ pdb_file = m_file_up.get();
+ }
+
+ if (!pdb_file)
+ return 0;
+
+ auto expected_index = PdbIndex::create(pdb_file);
+ if (!expected_index) {
+ llvm::consumeError(expected_index.takeError());
+ return 0;
+ }
+ m_index = std::move(*expected_index);
+ }
+ if (!m_index)
+ return 0;
+
+ // We don't especially have to be precise here. We only distinguish between
+ // stripped and not stripped.
+ abilities = kAllAbilities;
+
+ if (m_index->dbi().isStripped())
+ abilities &= ~(Blocks | LocalVariables);
+ return abilities;
+}
+
+void SymbolFileNativePDB::InitializeObject() {
+ m_obj_load_address = m_objfile_sp->GetModule()
+ ->GetObjectFile()
+ ->GetBaseAddress()
+ .GetFileAddress();
+ m_index->SetLoadAddress(m_obj_load_address);
+ m_index->ParseSectionContribs();
+
+ auto ts_or_err = m_objfile_sp->GetModule()->GetTypeSystemForLanguage(
+ lldb::eLanguageTypeC_plus_plus);
+ if (auto err = ts_or_err.takeError()) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Symbols), std::move(err),
+ "Failed to initialize: {0}");
+ } else {
+ if (auto ts = *ts_or_err)
+ ts->SetSymbolFile(this);
+ BuildParentMap();
+ }
+}
+
+uint32_t SymbolFileNativePDB::CalculateNumCompileUnits() {
+ const DbiModuleList &modules = m_index->dbi().modules();
+ uint32_t count = modules.getModuleCount();
+ if (count == 0)
+ return count;
+
+ // The linker can inject an additional "dummy" compilation unit into the
+ // PDB. Ignore this special compile unit for our purposes, if it is there.
+ // It is always the last one.
+ DbiModuleDescriptor last = modules.getModuleDescriptor(count - 1);
+ if (last.getModuleName() == "* Linker *")
+ --count;
+ return count;
+}
+
+Block &SymbolFileNativePDB::CreateBlock(PdbCompilandSymId block_id) {
+ CompilandIndexItem *cii = m_index->compilands().GetCompiland(block_id.modi);
+ CVSymbol sym = cii->m_debug_stream.readSymbolAtOffset(block_id.offset);
+ CompUnitSP comp_unit = GetOrCreateCompileUnit(*cii);
+ lldb::user_id_t opaque_block_uid = toOpaqueUid(block_id);
+ BlockSP child_block = std::make_shared<Block>(opaque_block_uid);
+ auto ts_or_err = GetTypeSystemForLanguage(comp_unit->GetLanguage());
+ if (auto err = ts_or_err.takeError())
+ return *child_block;
+ auto ts = *ts_or_err;
+ if (!ts)
+ return *child_block;
+ PdbAstBuilder* ast_builder = ts->GetNativePDBParser();
+
+ switch (sym.kind()) {
+ case S_GPROC32:
+ case S_LPROC32: {
+ // This is a function. It must be global. Creating the Function entry
+ // for it automatically creates a block for it.
+ FunctionSP func = GetOrCreateFunction(block_id, *comp_unit);
+ if (func) {
+ Block &block = func->GetBlock(false);
+ if (block.GetNumRanges() == 0)
+ block.AddRange(Block::Range(0, func->GetAddressRange().GetByteSize()));
+ return block;
+ }
+ break;
+ }
+ case S_BLOCK32: {
+ // This is a block. Its parent is either a function or another block. In
+ // either case, its parent can be viewed as a block (e.g. a function
+ // contains 1 big block. So just get the parent block and add this block
+ // to it.
+ BlockSym block(static_cast<SymbolRecordKind>(sym.kind()));
+ cantFail(SymbolDeserializer::deserializeAs<BlockSym>(sym, block));
+ lldbassert(block.Parent != 0);
+ PdbCompilandSymId parent_id(block_id.modi, block.Parent);
+ Block &parent_block = GetOrCreateBlock(parent_id);
+ Function *func = parent_block.CalculateSymbolContextFunction();
+ lldbassert(func);
+ lldb::addr_t block_base =
+ m_index->MakeVirtualAddress(block.Segment, block.CodeOffset);
+ lldb::addr_t func_base =
+ func->GetAddressRange().GetBaseAddress().GetFileAddress();
+ if (block_base >= func_base)
+ child_block->AddRange(Block::Range(block_base - func_base, block.CodeSize));
+ else {
+ GetObjectFile()->GetModule()->ReportError(
+ "S_BLOCK32 at modi: {0:d} offset: {1:d}: adding range "
+ "[{2:x16}-{3:x16}) which has a base that is less than the "
+ "function's "
+ "low PC 0x%" PRIx64 ". Please file a bug and attach the file at the "
+ "start of this error message",
+ block_id.modi, block_id.offset, block_base,
+ block_base + block.CodeSize, func_base);
+ }
+ parent_block.AddChild(child_block);
+ ast_builder->GetOrCreateBlockDecl(block_id);
+ m_blocks.insert({opaque_block_uid, child_block});
+ break;
+ }
+ case S_INLINESITE: {
+ // This ensures line table is parsed first so we have inline sites info.
+ comp_unit->GetLineTable();
+
+ std::shared_ptr<InlineSite> inline_site = m_inline_sites[opaque_block_uid];
+ Block &parent_block = GetOrCreateBlock(inline_site->parent_id);
+ parent_block.AddChild(child_block);
+ ast_builder->GetOrCreateInlinedFunctionDecl(block_id);
+ // Copy ranges from InlineSite to Block.
+ for (size_t i = 0; i < inline_site->ranges.GetSize(); ++i) {
+ auto *entry = inline_site->ranges.GetEntryAtIndex(i);
+ child_block->AddRange(
+ Block::Range(entry->GetRangeBase(), entry->GetByteSize()));
+ }
+ child_block->FinalizeRanges();
+
+ // Get the inlined function callsite info.
+ Declaration &decl = inline_site->inline_function_info->GetDeclaration();
+ Declaration &callsite = inline_site->inline_function_info->GetCallSite();
+ child_block->SetInlinedFunctionInfo(
+ inline_site->inline_function_info->GetName().GetCString(), nullptr,
+ &decl, &callsite);
+ m_blocks.insert({opaque_block_uid, child_block});
+ break;
+ }
+ default:
+ lldbassert(false && "Symbol is not a block!");
+ }
+
+ return *child_block;
+}
+
+lldb::FunctionSP SymbolFileNativePDB::CreateFunction(PdbCompilandSymId func_id,
+ CompileUnit &comp_unit) {
+ const CompilandIndexItem *cci =
+ m_index->compilands().GetCompiland(func_id.modi);
+ lldbassert(cci);
+ CVSymbol sym_record = cci->m_debug_stream.readSymbolAtOffset(func_id.offset);
+
+ lldbassert(sym_record.kind() == S_LPROC32 || sym_record.kind() == S_GPROC32);
+ SegmentOffsetLength sol = GetSegmentOffsetAndLength(sym_record);
+
+ auto file_vm_addr =
+ m_index->MakeVirtualAddress(sol.so.segment, sol.so.offset);
+ if (file_vm_addr == LLDB_INVALID_ADDRESS || file_vm_addr == 0)
+ return nullptr;
+
+ AddressRange func_range(file_vm_addr, sol.length,
+ comp_unit.GetModule()->GetSectionList());
+ if (!func_range.GetBaseAddress().IsValid())
+ return nullptr;
+
+ ProcSym proc(static_cast<SymbolRecordKind>(sym_record.kind()));
+ cantFail(SymbolDeserializer::deserializeAs<ProcSym>(sym_record, proc));
+ if (proc.FunctionType == TypeIndex::None())
+ return nullptr;
+ TypeSP func_type = GetOrCreateType(proc.FunctionType);
+ if (!func_type)
+ return nullptr;
+
+ PdbTypeSymId sig_id(proc.FunctionType, false);
+ Mangled mangled(proc.Name);
+ FunctionSP func_sp = std::make_shared<Function>(
+ &comp_unit, toOpaqueUid(func_id), toOpaqueUid(sig_id), mangled,
+ func_type.get(), func_range);
+
+ comp_unit.AddFunction(func_sp);
+
+ auto ts_or_err = GetTypeSystemForLanguage(comp_unit.GetLanguage());
+ if (auto err = ts_or_err.takeError())
+ return func_sp;
+ auto ts = *ts_or_err;
+ if (!ts)
+ return func_sp;
+ ts->GetNativePDBParser()->GetOrCreateFunctionDecl(func_id);
+
+ return func_sp;
+}
+
+CompUnitSP
+SymbolFileNativePDB::CreateCompileUnit(const CompilandIndexItem &cci) {
+ lldb::LanguageType lang =
+ cci.m_compile_opts ? TranslateLanguage(cci.m_compile_opts->getLanguage())
+ : lldb::eLanguageTypeUnknown;
+
+ LazyBool optimized = eLazyBoolNo;
+ if (cci.m_compile_opts && cci.m_compile_opts->hasOptimizations())
+ optimized = eLazyBoolYes;
+
+ llvm::SmallString<64> source_file_name =
+ m_index->compilands().GetMainSourceFile(cci);
+ FileSpec fs(llvm::sys::path::convert_to_slash(
+ source_file_name, llvm::sys::path::Style::windows_backslash));
+
+ CompUnitSP cu_sp = std::make_shared<CompileUnit>(
+ m_objfile_sp->GetModule(), nullptr, std::make_shared<SupportFile>(fs),
+ toOpaqueUid(cci.m_id), lang, optimized);
+
+ SetCompileUnitAtIndex(cci.m_id.modi, cu_sp);
+ return cu_sp;
+}
+
+lldb::TypeSP SymbolFileNativePDB::CreateModifierType(PdbTypeSymId type_id,
+ const ModifierRecord &mr,
+ CompilerType ct) {
+ TpiStream &stream = m_index->tpi();
+
+ std::string name;
+ if (mr.ModifiedType.isSimple())
+ name = std::string(GetSimpleTypeName(mr.ModifiedType.getSimpleKind()));
+ else
+ name = computeTypeName(stream.typeCollection(), mr.ModifiedType);
+ Declaration decl;
+ lldb::TypeSP modified_type = GetOrCreateType(mr.ModifiedType);
+
+ return MakeType(toOpaqueUid(type_id), ConstString(name),
+ modified_type->GetByteSize(nullptr), nullptr,
+ LLDB_INVALID_UID, Type::eEncodingIsUID, decl, ct,
+ Type::ResolveState::Full);
+}
+
+lldb::TypeSP
+SymbolFileNativePDB::CreatePointerType(PdbTypeSymId type_id,
+ const llvm::codeview::PointerRecord &pr,
+ CompilerType ct) {
+ TypeSP pointee = GetOrCreateType(pr.ReferentType);
+ if (!pointee)
+ return nullptr;
+
+ if (pr.isPointerToMember()) {
+ MemberPointerInfo mpi = pr.getMemberInfo();
+ GetOrCreateType(mpi.ContainingType);
+ }
+
+ Declaration decl;
+ return MakeType(toOpaqueUid(type_id), ConstString(), pr.getSize(), nullptr,
+ LLDB_INVALID_UID, Type::eEncodingIsUID, decl, ct,
+ Type::ResolveState::Full);
+}
+
+lldb::TypeSP SymbolFileNativePDB::CreateSimpleType(TypeIndex ti,
+ CompilerType ct) {
+ uint64_t uid = toOpaqueUid(PdbTypeSymId(ti, false));
+ if (ti == TypeIndex::NullptrT()) {
+ Declaration decl;
+ return MakeType(uid, ConstString("std::nullptr_t"), 0, nullptr,
+ LLDB_INVALID_UID, Type::eEncodingIsUID, decl, ct,
+ Type::ResolveState::Full);
+ }
+
+ if (ti.getSimpleMode() != SimpleTypeMode::Direct) {
+ TypeSP direct_sp = GetOrCreateType(ti.makeDirect());
+ uint32_t pointer_size = 0;
+ switch (ti.getSimpleMode()) {
+ case SimpleTypeMode::FarPointer32:
+ case SimpleTypeMode::NearPointer32:
+ pointer_size = 4;
+ break;
+ case SimpleTypeMode::NearPointer64:
+ pointer_size = 8;
+ break;
+ default:
+ // 128-bit and 16-bit pointers unsupported.
+ return nullptr;
+ }
+ Declaration decl;
+ return MakeType(uid, ConstString(), pointer_size, nullptr, LLDB_INVALID_UID,
+ Type::eEncodingIsUID, decl, ct, Type::ResolveState::Full);
+ }
+
+ if (ti.getSimpleKind() == SimpleTypeKind::NotTranslated)
+ return nullptr;
+
+ size_t size = GetTypeSizeForSimpleKind(ti.getSimpleKind());
+ llvm::StringRef type_name = GetSimpleTypeName(ti.getSimpleKind());
+
+ Declaration decl;
+ return MakeType(uid, ConstString(type_name), size, nullptr, LLDB_INVALID_UID,
+ Type::eEncodingIsUID, decl, ct, Type::ResolveState::Full);
+}
+
+static std::string GetUnqualifiedTypeName(const TagRecord &record) {
+ if (!record.hasUniqueName()) {
+ MSVCUndecoratedNameParser parser(record.Name);
+ llvm::ArrayRef<MSVCUndecoratedNameSpecifier> specs = parser.GetSpecifiers();
+
+ return std::string(specs.back().GetBaseName());
+ }
+
+ llvm::ms_demangle::Demangler demangler;
+ std::string_view sv(record.UniqueName.begin(), record.UniqueName.size());
+ llvm::ms_demangle::TagTypeNode *ttn = demangler.parseTagUniqueName(sv);
+ if (demangler.Error)
+ return std::string(record.Name);
+
+ llvm::ms_demangle::IdentifierNode *idn =
+ ttn->QualifiedName->getUnqualifiedIdentifier();
+ return idn->toString();
+}
+
+lldb::TypeSP
+SymbolFileNativePDB::CreateClassStructUnion(PdbTypeSymId type_id,
+ const TagRecord &record,
+ size_t size, CompilerType ct) {
+
+ std::string uname = GetUnqualifiedTypeName(record);
+
+ // FIXME: Search IPI stream for LF_UDT_MOD_SRC_LINE.
+ Declaration decl;
+ return MakeType(toOpaqueUid(type_id), ConstString(uname), size, nullptr,
+ LLDB_INVALID_UID, Type::eEncodingIsUID, decl, ct,
+ Type::ResolveState::Forward);
+}
+
+lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbTypeSymId type_id,
+ const ClassRecord &cr,
+ CompilerType ct) {
+ return CreateClassStructUnion(type_id, cr, cr.getSize(), ct);
+}
+
+lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbTypeSymId type_id,
+ const UnionRecord &ur,
+ CompilerType ct) {
+ return CreateClassStructUnion(type_id, ur, ur.getSize(), ct);
+}
+
+lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbTypeSymId type_id,
+ const EnumRecord &er,
+ CompilerType ct) {
+ std::string uname = GetUnqualifiedTypeName(er);
+
+ Declaration decl;
+ TypeSP underlying_type = GetOrCreateType(er.UnderlyingType);
+
+ return MakeType(toOpaqueUid(type_id), ConstString(uname),
+ underlying_type->GetByteSize(nullptr), nullptr,
+ LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl,
+ ct, lldb_private::Type::ResolveState::Forward);
+}
+
+TypeSP SymbolFileNativePDB::CreateArrayType(PdbTypeSymId type_id,
+ const ArrayRecord &ar,
+ CompilerType ct) {
+ TypeSP element_type = GetOrCreateType(ar.ElementType);
+
+ Declaration decl;
+ TypeSP array_sp =
+ MakeType(toOpaqueUid(type_id), ConstString(), ar.Size, nullptr,
+ LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, ct,
+ lldb_private::Type::ResolveState::Full);
+ array_sp->SetEncodingType(element_type.get());
+ return array_sp;
+}
+
+TypeSP SymbolFileNativePDB::CreateFunctionType(PdbTypeSymId type_id,
+ const MemberFunctionRecord &mfr,
+ CompilerType ct) {
+ Declaration decl;
+ return MakeType(toOpaqueUid(type_id), ConstString(), 0, nullptr,
+ LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl,
+ ct, lldb_private::Type::ResolveState::Full);
+}
+
+TypeSP SymbolFileNativePDB::CreateProcedureType(PdbTypeSymId type_id,
+ const ProcedureRecord &pr,
+ CompilerType ct) {
+ Declaration decl;
+ return MakeType(toOpaqueUid(type_id), ConstString(), 0, nullptr,
+ LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl,
+ ct, lldb_private::Type::ResolveState::Full);
+}
+
+TypeSP SymbolFileNativePDB::CreateType(PdbTypeSymId type_id, CompilerType ct) {
+ if (type_id.index.isSimple())
+ return CreateSimpleType(type_id.index, ct);
+
+ TpiStream &stream = type_id.is_ipi ? m_index->ipi() : m_index->tpi();
+ CVType cvt = stream.getType(type_id.index);
+
+ if (cvt.kind() == LF_MODIFIER) {
+ ModifierRecord modifier;
+ llvm::cantFail(
+ TypeDeserializer::deserializeAs<ModifierRecord>(cvt, modifier));
+ return CreateModifierType(type_id, modifier, ct);
+ }
+
+ if (cvt.kind() == LF_POINTER) {
+ PointerRecord pointer;
+ llvm::cantFail(
+ TypeDeserializer::deserializeAs<PointerRecord>(cvt, pointer));
+ return CreatePointerType(type_id, pointer, ct);
+ }
+
+ if (IsClassRecord(cvt.kind())) {
+ ClassRecord cr;
+ llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, cr));
+ return CreateTagType(type_id, cr, ct);
+ }
+
+ if (cvt.kind() == LF_ENUM) {
+ EnumRecord er;
+ llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));
+ return CreateTagType(type_id, er, ct);
+ }
+
+ if (cvt.kind() == LF_UNION) {
+ UnionRecord ur;
+ llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, ur));
+ return CreateTagType(type_id, ur, ct);
+ }
+
+ if (cvt.kind() == LF_ARRAY) {
+ ArrayRecord ar;
+ llvm::cantFail(TypeDeserializer::deserializeAs<ArrayRecord>(cvt, ar));
+ return CreateArrayType(type_id, ar, ct);
+ }
+
+ if (cvt.kind() == LF_PROCEDURE) {
+ ProcedureRecord pr;
+ llvm::cantFail(TypeDeserializer::deserializeAs<ProcedureRecord>(cvt, pr));
+ return CreateProcedureType(type_id, pr, ct);
+ }
+ if (cvt.kind() == LF_MFUNCTION) {
+ MemberFunctionRecord mfr;
+ llvm::cantFail(TypeDeserializer::deserializeAs<MemberFunctionRecord>(cvt, mfr));
+ return CreateFunctionType(type_id, mfr, ct);
+ }
+
+ return nullptr;
+}
+
+TypeSP SymbolFileNativePDB::CreateAndCacheType(PdbTypeSymId type_id) {
+ // If they search for a UDT which is a forward ref, try and resolve the full
+ // decl and just map the forward ref uid to the full decl record.
+ std::optional<PdbTypeSymId> full_decl_uid;
+ if (IsForwardRefUdt(type_id, m_index->tpi())) {
+ auto expected_full_ti =
+ m_index->tpi().findFullDeclForForwardRef(type_id.index);
+ if (!expected_full_ti)
+ llvm::consumeError(expected_full_ti.takeError());
+ else if (*expected_full_ti != type_id.index) {
+ full_decl_uid = PdbTypeSymId(*expected_full_ti, false);
+
+ // It's possible that a lookup would occur for the full decl causing it
+ // to be cached, then a second lookup would occur for the forward decl.
+ // We don't want to create a second full decl, so make sure the full
+ // decl hasn't already been cached.
+ auto full_iter = m_types.find(toOpaqueUid(*full_decl_uid));
+ if (full_iter != m_types.end()) {
+ TypeSP result = full_iter->second;
+ // Map the forward decl to the TypeSP for the full decl so we can take
+ // the fast path next time.
+ m_types[toOpaqueUid(type_id)] = result;
+ return result;
+ }
+ }
+ }
+
+ PdbTypeSymId best_decl_id = full_decl_uid ? *full_decl_uid : type_id;
+ auto ts_or_err = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
+ if (auto err = ts_or_err.takeError())
+ return nullptr;
+ auto ts = *ts_or_err;
+ if (!ts)
+ return nullptr;
+
+ PdbAstBuilder* ast_builder = ts->GetNativePDBParser();
+ clang::QualType qt = ast_builder->GetOrCreateType(best_decl_id);
+ if (qt.isNull())
+ return nullptr;
+
+ TypeSP result = CreateType(best_decl_id, ast_builder->ToCompilerType(qt));
+ if (!result)
+ return nullptr;
+
+ uint64_t best_uid = toOpaqueUid(best_decl_id);
+ m_types[best_uid] = result;
+ // If we had both a forward decl and a full decl, make both point to the new
+ // type.
+ if (full_decl_uid)
+ m_types[toOpaqueUid(type_id)] = result;
+
+ return result;
+}
+
+TypeSP SymbolFileNativePDB::GetOrCreateType(PdbTypeSymId type_id) {
+ // We can't use try_emplace / overwrite here because the process of creating
+ // a type could create nested types, which could invalidate iterators. So
+ // we have to do a 2-phase lookup / insert.
+ auto iter = m_types.find(toOpaqueUid(type_id));
+ if (iter != m_types.end())
+ return iter->second;
+
+ TypeSP type = CreateAndCacheType(type_id);
+ if (type)
+ GetTypeList().Insert(type);
+ return type;
+}
+
+VariableSP SymbolFileNativePDB::CreateGlobalVariable(PdbGlobalSymId var_id) {
+ CVSymbol sym = m_index->symrecords().readRecord(var_id.offset);
+ if (sym.kind() == S_CONSTANT)
+ return CreateConstantSymbol(var_id, sym);
+
+ lldb::ValueType scope = eValueTypeInvalid;
+ TypeIndex ti;
+ llvm::StringRef name;
+ lldb::addr_t addr = 0;
+ uint16_t section = 0;
+ uint32_t offset = 0;
+ bool is_external = false;
+ switch (sym.kind()) {
+ case S_GDATA32:
+ is_external = true;
+ [[fallthrough]];
+ case S_LDATA32: {
+ DataSym ds(sym.kind());
+ llvm::cantFail(SymbolDeserializer::deserializeAs<DataSym>(sym, ds));
+ ti = ds.Type;
+ scope = (sym.kind() == S_GDATA32) ? eValueTypeVariableGlobal
+ : eValueTypeVariableStatic;
+ name = ds.Name;
+ section = ds.Segment;
+ offset = ds.DataOffset;
+ addr = m_index->MakeVirtualAddress(ds.Segment, ds.DataOffset);
+ break;
+ }
+ case S_GTHREAD32:
+ is_external = true;
+ [[fallthrough]];
+ case S_LTHREAD32: {
+ ThreadLocalDataSym tlds(sym.kind());
+ llvm::cantFail(
+ SymbolDeserializer::deserializeAs<ThreadLocalDataSym>(sym, tlds));
+ ti = tlds.Type;
+ name = tlds.Name;
+ section = tlds.Segment;
+ offset = tlds.DataOffset;
+ addr = m_index->MakeVirtualAddress(tlds.Segment, tlds.DataOffset);
+ scope = eValueTypeVariableThreadLocal;
+ break;
+ }
+ default:
+ llvm_unreachable("unreachable!");
+ }
+
+ CompUnitSP comp_unit;
+ std::optional<uint16_t> modi = m_index->GetModuleIndexForVa(addr);
+ if (!modi) {
+ return nullptr;
+ }
+
+ CompilandIndexItem &cci = m_index->compilands().GetOrCreateCompiland(*modi);
+ comp_unit = GetOrCreateCompileUnit(cci);
+
+ Declaration decl;
+ PdbTypeSymId tid(ti, false);
+ SymbolFileTypeSP type_sp =
+ std::make_shared<SymbolFileType>(*this, toOpaqueUid(tid));
+ Variable::RangeList ranges;
+ auto ts_or_err = GetTypeSystemForLanguage(comp_unit->GetLanguage());
+ if (auto err = ts_or_err.takeError())
+ return nullptr;
+ auto ts = *ts_or_err;
+ if (!ts)
+ return nullptr;
+
+ ts->GetNativePDBParser()->GetOrCreateVariableDecl(var_id);
+
+ ModuleSP module_sp = GetObjectFile()->GetModule();
+ DWARFExpressionList location(
+ module_sp, MakeGlobalLocationExpression(section, offset, module_sp),
+ nullptr);
+
+ std::string global_name("::");
+ global_name += name;
+ bool artificial = false;
+ bool location_is_constant_data = false;
+ bool static_member = false;
+ VariableSP var_sp = std::make_shared<Variable>(
+ toOpaqueUid(var_id), name.str().c_str(), global_name.c_str(), type_sp,
+ scope, comp_unit.get(), ranges, &decl, location, is_external, artificial,
+ location_is_constant_data, static_member);
+
+ return var_sp;
+}
+
+lldb::VariableSP
+SymbolFileNativePDB::CreateConstantSymbol(PdbGlobalSymId var_id,
+ const CVSymbol &cvs) {
+ TpiStream &tpi = m_index->tpi();
+ ConstantSym constant(cvs.kind());
+
+ llvm::cantFail(SymbolDeserializer::deserializeAs<ConstantSym>(cvs, constant));
+ std::string global_name("::");
+ global_name += constant.Name;
+ PdbTypeSymId tid(constant.Type, false);
+ SymbolFileTypeSP type_sp =
+ std::make_shared<SymbolFileType>(*this, toOpaqueUid(tid));
+
+ Declaration decl;
+ Variable::RangeList ranges;
+ ModuleSP module = GetObjectFile()->GetModule();
+ DWARFExpressionList location(module,
+ MakeConstantLocationExpression(
+ constant.Type, tpi, constant.Value, module),
+ nullptr);
+
+ bool external = false;
+ bool artificial = false;
+ bool location_is_constant_data = true;
+ bool static_member = false;
+ VariableSP var_sp = std::make_shared<Variable>(
+ toOpaqueUid(var_id), constant.Name.str().c_str(), global_name.c_str(),
+ type_sp, eValueTypeVariableGlobal, module.get(), ranges, &decl, location,
+ external, artificial, location_is_constant_data, static_member);
+ return var_sp;
+}
+
+VariableSP
+SymbolFileNativePDB::GetOrCreateGlobalVariable(PdbGlobalSymId var_id) {
+ auto emplace_result = m_global_vars.try_emplace(toOpaqueUid(var_id), nullptr);
+ if (emplace_result.second) {
+ if (VariableSP var_sp = CreateGlobalVariable(var_id))
+ emplace_result.first->second = var_sp;
+ else
+ return nullptr;
+ }
+
+ return emplace_result.first->second;
+}
+
+lldb::TypeSP SymbolFileNativePDB::GetOrCreateType(TypeIndex ti) {
+ return GetOrCreateType(PdbTypeSymId(ti, false));
+}
+
+FunctionSP SymbolFileNativePDB::GetOrCreateFunction(PdbCompilandSymId func_id,
+ CompileUnit &comp_unit) {
+ auto emplace_result = m_functions.try_emplace(toOpaqueUid(func_id), nullptr);
+ if (emplace_result.second)
+ emplace_result.first->second = CreateFunction(func_id, comp_unit);
+
+ return emplace_result.first->second;
+}
+
+CompUnitSP
+SymbolFileNativePDB::GetOrCreateCompileUnit(const CompilandIndexItem &cci) {
+
+ auto emplace_result =
+ m_compilands.try_emplace(toOpaqueUid(cci.m_id), nullptr);
+ if (emplace_result.second)
+ emplace_result.first->second = CreateCompileUnit(cci);
+
+ lldbassert(emplace_result.first->second);
+ return emplace_result.first->second;
+}
+
+Block &SymbolFileNativePDB::GetOrCreateBlock(PdbCompilandSymId block_id) {
+ auto iter = m_blocks.find(toOpaqueUid(block_id));
+ if (iter != m_blocks.end())
+ return *iter->second;
+
+ return CreateBlock(block_id);
+}
+
+void SymbolFileNativePDB::ParseDeclsForContext(
+ lldb_private::CompilerDeclContext decl_ctx) {
+ TypeSystem* ts_or_err = decl_ctx.GetTypeSystem();
+ if (!ts_or_err)
+ return;
+ PdbAstBuilder* ast_builder = ts_or_err->GetNativePDBParser();
+ clang::DeclContext *context = ast_builder->FromCompilerDeclContext(decl_ctx);
+ if (!context)
+ return;
+ ast_builder->ParseDeclsForContext(*context);
+}
+
+lldb::CompUnitSP SymbolFileNativePDB::ParseCompileUnitAtIndex(uint32_t index) {
+ if (index >= GetNumCompileUnits())
+ return CompUnitSP();
+ lldbassert(index < UINT16_MAX);
+ if (index >= UINT16_MAX)
+ return nullptr;
+
+ CompilandIndexItem &item = m_index->compilands().GetOrCreateCompiland(index);
+
+ return GetOrCreateCompileUnit(item);
+}
+
+lldb::LanguageType SymbolFileNativePDB::ParseLanguage(CompileUnit &comp_unit) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ PdbSymUid uid(comp_unit.GetID());
+ lldbassert(uid.kind() == PdbSymUidKind::Compiland);
+
+ CompilandIndexItem *item =
+ m_index->compilands().GetCompiland(uid.asCompiland().modi);
+ lldbassert(item);
+ if (!item->m_compile_opts)
+ return lldb::eLanguageTypeUnknown;
+
+ return TranslateLanguage(item->m_compile_opts->getLanguage());
+}
+
+void SymbolFileNativePDB::AddSymbols(Symtab &symtab) {}
+
+size_t SymbolFileNativePDB::ParseFunctions(CompileUnit &comp_unit) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ PdbSymUid uid{comp_unit.GetID()};
+ lldbassert(uid.kind() == PdbSymUidKind::Compiland);
+ uint16_t modi = uid.asCompiland().modi;
+ CompilandIndexItem &cii = m_index->compilands().GetOrCreateCompiland(modi);
+
+ size_t count = comp_unit.GetNumFunctions();
+ const CVSymbolArray &syms = cii.m_debug_stream.getSymbolArray();
+ for (auto iter = syms.begin(); iter != syms.end(); ++iter) {
+ if (iter->kind() != S_LPROC32 && iter->kind() != S_GPROC32)
+ continue;
+
+ PdbCompilandSymId sym_id{modi, iter.offset()};
+
+ FunctionSP func = GetOrCreateFunction(sym_id, comp_unit);
+ }
+
+ size_t new_count = comp_unit.GetNumFunctions();
+ lldbassert(new_count >= count);
+ return new_count - count;
+}
+
+static bool NeedsResolvedCompileUnit(uint32_t resolve_scope) {
+ // If any of these flags are set, we need to resolve the compile unit.
+ uint32_t flags = eSymbolContextCompUnit;
+ flags |= eSymbolContextVariable;
+ flags |= eSymbolContextFunction;
+ flags |= eSymbolContextBlock;
+ flags |= eSymbolContextLineEntry;
+ return (resolve_scope & flags) != 0;
+}
+
+uint32_t SymbolFileNativePDB::ResolveSymbolContext(
+ const Address &addr, SymbolContextItem resolve_scope, SymbolContext &sc) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ uint32_t resolved_flags = 0;
+ lldb::addr_t file_addr = addr.GetFileAddress();
+
+ if (NeedsResolvedCompileUnit(resolve_scope)) {
+ std::optional<uint16_t> modi = m_index->GetModuleIndexForVa(file_addr);
+ if (!modi)
+ return 0;
+ CompUnitSP cu_sp = GetCompileUnitAtIndex(*modi);
+ if (!cu_sp)
+ return 0;
+
+ sc.comp_unit = cu_sp.get();
+ resolved_flags |= eSymbolContextCompUnit;
+ }
+
+ if (resolve_scope & eSymbolContextFunction ||
+ resolve_scope & eSymbolContextBlock) {
+ lldbassert(sc.comp_unit);
+ std::vector<SymbolAndUid> matches = m_index->FindSymbolsByVa(file_addr);
+ // Search the matches in reverse. This way if there are multiple matches
+ // (for example we are 3 levels deep in a nested scope) it will find the
+ // innermost one first.
+ for (const auto &match : llvm::reverse(matches)) {
+ if (match.uid.kind() != PdbSymUidKind::CompilandSym)
+ continue;
+
+ PdbCompilandSymId csid = match.uid.asCompilandSym();
+ CVSymbol cvs = m_index->ReadSymbolRecord(csid);
+ PDB_SymType type = CVSymToPDBSym(cvs.kind());
+ if (type != PDB_SymType::Function && type != PDB_SymType::Block)
+ continue;
+ if (type == PDB_SymType::Function) {
+ sc.function = GetOrCreateFunction(csid, *sc.comp_unit).get();
+ if (sc.function) {
+ Block &block = sc.function->GetBlock(true);
+ addr_t func_base =
+ sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
+ addr_t offset = file_addr - func_base;
+ sc.block = block.FindInnermostBlockByOffset(offset);
+ }
+ }
+
+ if (type == PDB_SymType::Block) {
+ Block &block = GetOrCreateBlock(csid);
+ sc.function = block.CalculateSymbolContextFunction();
+ if (sc.function) {
+ sc.function->GetBlock(true);
+ addr_t func_base =
+ sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
+ addr_t offset = file_addr - func_base;
+ sc.block = block.FindInnermostBlockByOffset(offset);
+ }
+ }
+ if (sc.function)
+ resolved_flags |= eSymbolContextFunction;
+ if (sc.block)
+ resolved_flags |= eSymbolContextBlock;
+ break;
+ }
+ }
+
+ if (resolve_scope & eSymbolContextLineEntry) {
+ lldbassert(sc.comp_unit);
+ if (auto *line_table = sc.comp_unit->GetLineTable()) {
+ if (line_table->FindLineEntryByAddress(addr, sc.line_entry))
+ resolved_flags |= eSymbolContextLineEntry;
+ }
+ }
+
+ return resolved_flags;
+}
+
+uint32_t SymbolFileNativePDB::ResolveSymbolContext(
+ const SourceLocationSpec &src_location_spec,
+ lldb::SymbolContextItem resolve_scope, SymbolContextList &sc_list) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ 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 *cu = ParseCompileUnitAtIndex(cu_idx).get();
+ if (!cu)
+ continue;
+
+ bool file_spec_matches_cu_file_spec = FileSpec::Match(
+ src_location_spec.GetFileSpec(), cu->GetPrimaryFile());
+ if (file_spec_matches_cu_file_spec) {
+ cu->ResolveSymbolContext(src_location_spec, resolve_scope, sc_list);
+ break;
+ }
+ }
+ }
+ return sc_list.GetSize() - prev_size;
+}
+
+bool SymbolFileNativePDB::ParseLineTable(CompileUnit &comp_unit) {
+ // Unfortunately LLDB is set up to parse the entire compile unit line table
+ // all at once, even if all it really needs is line info for a specific
+ // function. In the future it would be nice if it could set the sc.m_function
+ // member, and we could only get the line info for the function in question.
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ PdbSymUid cu_id(comp_unit.GetID());
+ lldbassert(cu_id.kind() == PdbSymUidKind::Compiland);
+ uint16_t modi = cu_id.asCompiland().modi;
+ CompilandIndexItem *cii = m_index->compilands().GetCompiland(modi);
+ lldbassert(cii);
+
+ // Parse DEBUG_S_LINES subsections first, then parse all S_INLINESITE records
+ // in this CU. Add line entries into the set first so that if there are line
+ // entries with same addres, the later is always more accurate than the
+ // former.
+ std::set<LineTable::Entry, LineTableEntryComparator> line_set;
+
+ // This is basically a copy of the .debug$S subsections from all original COFF
+ // object files merged together with address relocations applied. We are
+ // looking for all DEBUG_S_LINES subsections.
+ for (const DebugSubsectionRecord &dssr :
+ cii->m_debug_stream.getSubsectionsArray()) {
+ if (dssr.kind() != DebugSubsectionKind::Lines)
+ continue;
+
+ DebugLinesSubsectionRef lines;
+ llvm::BinaryStreamReader reader(dssr.getRecordData());
+ if (auto EC = lines.initialize(reader)) {
+ llvm::consumeError(std::move(EC));
+ return false;
+ }
+
+ const LineFragmentHeader *lfh = lines.header();
+ uint64_t virtual_addr =
+ m_index->MakeVirtualAddress(lfh->RelocSegment, lfh->RelocOffset);
+ if (virtual_addr == LLDB_INVALID_ADDRESS)
+ continue;
+
+ for (const LineColumnEntry &group : lines) {
+ llvm::Expected<uint32_t> file_index_or_err =
+ GetFileIndex(*cii, group.NameIndex);
+ if (!file_index_or_err)
+ continue;
+ uint32_t file_index = file_index_or_err.get();
+ lldbassert(!group.LineNumbers.empty());
+ CompilandIndexItem::GlobalLineTable::Entry line_entry(
+ LLDB_INVALID_ADDRESS, 0);
+ for (const LineNumberEntry &entry : group.LineNumbers) {
+ LineInfo cur_info(entry.Flags);
+
+ if (cur_info.isAlwaysStepInto() || cur_info.isNeverStepInto())
+ continue;
+
+ uint64_t addr = virtual_addr + entry.Offset;
+
+ bool is_statement = cur_info.isStatement();
+ bool is_prologue = IsFunctionPrologue(*cii, addr);
+ bool is_epilogue = IsFunctionEpilogue(*cii, addr);
+
+ uint32_t lno = cur_info.getStartLine();
+
+ LineTable::Entry new_entry(addr, lno, 0, file_index, is_statement, false,
+ is_prologue, is_epilogue, false);
+ // Terminal entry has lower precedence than new entry.
+ auto iter = line_set.find(new_entry);
+ if (iter != line_set.end() && iter->is_terminal_entry)
+ line_set.erase(iter);
+ line_set.insert(new_entry);
+
+ if (line_entry.GetRangeBase() != LLDB_INVALID_ADDRESS) {
+ line_entry.SetRangeEnd(addr);
+ cii->m_global_line_table.Append(line_entry);
+ }
+ line_entry.SetRangeBase(addr);
+ line_entry.data = {file_index, lno};
+ }
+ LineInfo last_line(group.LineNumbers.back().Flags);
+ line_set.emplace(virtual_addr + lfh->CodeSize, last_line.getEndLine(), 0,
+ file_index, false, false, false, false, true);
+
+ if (line_entry.GetRangeBase() != LLDB_INVALID_ADDRESS) {
+ line_entry.SetRangeEnd(virtual_addr + lfh->CodeSize);
+ cii->m_global_line_table.Append(line_entry);
+ }
+ }
+ }
+
+ cii->m_global_line_table.Sort();
+
+ // Parse all S_INLINESITE in this CU.
+ const CVSymbolArray &syms = cii->m_debug_stream.getSymbolArray();
+ for (auto iter = syms.begin(); iter != syms.end();) {
+ if (iter->kind() != S_LPROC32 && iter->kind() != S_GPROC32) {
+ ++iter;
+ continue;
+ }
+
+ uint32_t record_offset = iter.offset();
+ CVSymbol func_record =
+ cii->m_debug_stream.readSymbolAtOffset(record_offset);
+ SegmentOffsetLength sol = GetSegmentOffsetAndLength(func_record);
+ addr_t file_vm_addr =
+ m_index->MakeVirtualAddress(sol.so.segment, sol.so.offset);
+ if (file_vm_addr == LLDB_INVALID_ADDRESS)
+ continue;
+
+ AddressRange func_range(file_vm_addr, sol.length,
+ comp_unit.GetModule()->GetSectionList());
+ Address func_base = func_range.GetBaseAddress();
+ PdbCompilandSymId func_id{modi, record_offset};
+
+ // Iterate all S_INLINESITEs in the function.
+ auto parse_inline_sites = [&](SymbolKind kind, PdbCompilandSymId id) {
+ if (kind != S_INLINESITE)
+ return false;
+
+ ParseInlineSite(id, func_base);
+
+ for (const auto &line_entry :
+ m_inline_sites[toOpaqueUid(id)]->line_entries) {
+ // If line_entry is not terminal entry, remove previous line entry at
+ // the same address and insert new one. Terminal entry inside an inline
+ // site might not be terminal entry for its parent.
+ if (!line_entry.is_terminal_entry)
+ line_set.erase(line_entry);
+ line_set.insert(line_entry);
+ }
+ // No longer useful after adding to line_set.
+ m_inline_sites[toOpaqueUid(id)]->line_entries.clear();
+ return true;
+ };
+ ParseSymbolArrayInScope(func_id, parse_inline_sites);
+ // Jump to the end of the function record.
+ iter = syms.at(getScopeEndOffset(func_record));
+ }
+
+ cii->m_global_line_table.Clear();
+
+ // Add line entries in line_set to line_table.
+ auto line_table = std::make_unique<LineTable>(&comp_unit);
+ std::unique_ptr<LineSequence> sequence(
+ line_table->CreateLineSequenceContainer());
+ for (const auto &line_entry : line_set) {
+ line_table->AppendLineEntryToSequence(
+ sequence.get(), line_entry.file_addr, line_entry.line,
+ line_entry.column, line_entry.file_idx,
+ line_entry.is_start_of_statement, line_entry.is_start_of_basic_block,
+ line_entry.is_prologue_end, line_entry.is_epilogue_begin,
+ line_entry.is_terminal_entry);
+ }
+ line_table->InsertSequence(sequence.get());
+
+ if (line_table->GetSize() == 0)
+ return false;
+
+ comp_unit.SetLineTable(line_table.release());
+ return true;
+}
+
+bool SymbolFileNativePDB::ParseDebugMacros(CompileUnit &comp_unit) {
+ // PDB doesn't contain information about macros
+ return false;
+}
+
+llvm::Expected<uint32_t>
+SymbolFileNativePDB::GetFileIndex(const CompilandIndexItem &cii,
+ uint32_t file_id) {
+ if (!cii.m_strings.hasChecksums() || !cii.m_strings.hasStrings())
+ return llvm::make_error<RawError>(raw_error_code::no_entry);
+
+ const auto &checksums = cii.m_strings.checksums().getArray();
+ const auto &strings = cii.m_strings.strings();
+ // Indices in this structure are actually offsets of records in the
+ // DEBUG_S_FILECHECKSUMS subsection. Those entries then have an index
+ // into the global PDB string table.
+ auto iter = checksums.at(file_id);
+ if (iter == checksums.end())
+ return llvm::make_error<RawError>(raw_error_code::no_entry);
+
+ llvm::Expected<llvm::StringRef> efn = strings.getString(iter->FileNameOffset);
+ if (!efn) {
+ return efn.takeError();
+ }
+
+ // LLDB wants the index of the file in the list of support files.
+ auto fn_iter = llvm::find(cii.m_file_list, *efn);
+ if (fn_iter != cii.m_file_list.end())
+ return std::distance(cii.m_file_list.begin(), fn_iter);
+ return llvm::make_error<RawError>(raw_error_code::no_entry);
+}
+
+bool SymbolFileNativePDB::ParseSupportFiles(CompileUnit &comp_unit,
+ SupportFileList &support_files) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ PdbSymUid cu_id(comp_unit.GetID());
+ lldbassert(cu_id.kind() == PdbSymUidKind::Compiland);
+ CompilandIndexItem *cci =
+ m_index->compilands().GetCompiland(cu_id.asCompiland().modi);
+ lldbassert(cci);
+
+ for (llvm::StringRef f : cci->m_file_list) {
+ FileSpec::Style style =
+ f.starts_with("/") ? FileSpec::Style::posix : FileSpec::Style::windows;
+ FileSpec spec(f, style);
+ support_files.Append(spec);
+ }
+ return true;
+}
+
+bool SymbolFileNativePDB::ParseImportedModules(
+ const SymbolContext &sc, std::vector<SourceModule> &imported_modules) {
+ // PDB does not yet support module debug info
+ return false;
+}
+
+void SymbolFileNativePDB::ParseInlineSite(PdbCompilandSymId id,
+ Address func_addr) {
+ lldb::user_id_t opaque_uid = toOpaqueUid(id);
+ if (m_inline_sites.contains(opaque_uid))
+ return;
+
+ addr_t func_base = func_addr.GetFileAddress();
+ CompilandIndexItem *cii = m_index->compilands().GetCompiland(id.modi);
+ CVSymbol sym = cii->m_debug_stream.readSymbolAtOffset(id.offset);
+ CompUnitSP comp_unit = GetOrCreateCompileUnit(*cii);
+
+ InlineSiteSym inline_site(static_cast<SymbolRecordKind>(sym.kind()));
+ cantFail(SymbolDeserializer::deserializeAs<InlineSiteSym>(sym, inline_site));
+ PdbCompilandSymId parent_id(id.modi, inline_site.Parent);
+
+ std::shared_ptr<InlineSite> inline_site_sp =
+ std::make_shared<InlineSite>(parent_id);
+
+ // Get the inlined function declaration info.
+ auto iter = cii->m_inline_map.find(inline_site.Inlinee);
+ if (iter == cii->m_inline_map.end())
+ return;
+ InlineeSourceLine inlinee_line = iter->second;
+
+ const SupportFileList &files = comp_unit->GetSupportFiles();
+ FileSpec decl_file;
+ llvm::Expected<uint32_t> file_index_or_err =
+ GetFileIndex(*cii, inlinee_line.Header->FileID);
+ if (!file_index_or_err)
+ return;
+ uint32_t file_offset = file_index_or_err.get();
+ decl_file = files.GetFileSpecAtIndex(file_offset);
+ uint32_t decl_line = inlinee_line.Header->SourceLineNum;
+ std::unique_ptr<Declaration> decl_up =
+ std::make_unique<Declaration>(decl_file, decl_line);
+
+ // Parse range and line info.
+ uint32_t code_offset = 0;
+ int32_t line_offset = 0;
+ std::optional<uint32_t> code_offset_base;
+ std::optional<uint32_t> code_offset_end;
+ std::optional<int32_t> cur_line_offset;
+ std::optional<int32_t> next_line_offset;
+ std::optional<uint32_t> next_file_offset;
+
+ bool is_terminal_entry = false;
+ bool is_start_of_statement = true;
+ // The first instruction is the prologue end.
+ bool is_prologue_end = true;
+
+ auto update_code_offset = [&](uint32_t code_delta) {
+ if (!code_offset_base)
+ code_offset_base = code_offset;
+ else if (!code_offset_end)
+ code_offset_end = *code_offset_base + code_delta;
+ };
+ auto update_line_offset = [&](int32_t line_delta) {
+ line_offset += line_delta;
+ if (!code_offset_base || !cur_line_offset)
+ cur_line_offset = line_offset;
+ else
+ next_line_offset = line_offset;
+ ;
+ };
+ auto update_file_offset = [&](uint32_t offset) {
+ if (!code_offset_base)
+ file_offset = offset;
+ else
+ next_file_offset = offset;
+ };
+
+ for (auto &annot : inline_site.annotations()) {
+ switch (annot.OpCode) {
+ case BinaryAnnotationsOpCode::CodeOffset:
+ case BinaryAnnotationsOpCode::ChangeCodeOffset:
+ case BinaryAnnotationsOpCode::ChangeCodeOffsetBase:
+ code_offset += annot.U1;
+ update_code_offset(annot.U1);
+ break;
+ case BinaryAnnotationsOpCode::ChangeLineOffset:
+ update_line_offset(annot.S1);
+ break;
+ case BinaryAnnotationsOpCode::ChangeCodeLength:
+ update_code_offset(annot.U1);
+ code_offset += annot.U1;
+ is_terminal_entry = true;
+ break;
+ case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset:
+ code_offset += annot.U1;
+ update_code_offset(annot.U1);
+ update_line_offset(annot.S1);
+ break;
+ case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset:
+ code_offset += annot.U2;
+ update_code_offset(annot.U2);
+ update_code_offset(annot.U1);
+ code_offset += annot.U1;
+ is_terminal_entry = true;
+ break;
+ case BinaryAnnotationsOpCode::ChangeFile:
+ update_file_offset(annot.U1);
+ break;
+ default:
+ break;
+ }
+
+ // Add range if current range is finished.
+ if (code_offset_base && code_offset_end && cur_line_offset) {
+ inline_site_sp->ranges.Append(RangeSourceLineVector::Entry(
+ *code_offset_base, *code_offset_end - *code_offset_base,
+ decl_line + *cur_line_offset));
+ // Set base, end, file offset and line offset for next range.
+ if (next_file_offset)
+ file_offset = *next_file_offset;
+ if (next_line_offset) {
+ cur_line_offset = next_line_offset;
+ next_line_offset = std::nullopt;
+ }
+ code_offset_base = is_terminal_entry ? std::nullopt : code_offset_end;
+ code_offset_end = next_file_offset = std::nullopt;
+ }
+ if (code_offset_base && cur_line_offset) {
+ if (is_terminal_entry) {
+ LineTable::Entry line_entry(
+ func_base + *code_offset_base, decl_line + *cur_line_offset, 0,
+ file_offset, false, false, false, false, true);
+ inline_site_sp->line_entries.push_back(line_entry);
+ } else {
+ LineTable::Entry line_entry(func_base + *code_offset_base,
+ decl_line + *cur_line_offset, 0,
+ file_offset, is_start_of_statement, false,
+ is_prologue_end, false, false);
+ inline_site_sp->line_entries.push_back(line_entry);
+ is_prologue_end = false;
+ is_start_of_statement = false;
+ }
+ }
+ if (is_terminal_entry)
+ is_start_of_statement = true;
+ is_terminal_entry = false;
+ }
+
+ inline_site_sp->ranges.Sort();
+
+ // Get the inlined function callsite info.
+ std::unique_ptr<Declaration> callsite_up;
+ if (!inline_site_sp->ranges.IsEmpty()) {
+ auto *entry = inline_site_sp->ranges.GetEntryAtIndex(0);
+ addr_t base_offset = entry->GetRangeBase();
+ if (cii->m_debug_stream.readSymbolAtOffset(parent_id.offset).kind() ==
+ S_INLINESITE) {
+ // Its parent is another inline site, lookup parent site's range vector
+ // for callsite line.
+ ParseInlineSite(parent_id, func_base);
+ std::shared_ptr<InlineSite> parent_site =
+ m_inline_sites[toOpaqueUid(parent_id)];
+ FileSpec &parent_decl_file =
+ parent_site->inline_function_info->GetDeclaration().GetFile();
+ if (auto *parent_entry =
+ parent_site->ranges.FindEntryThatContains(base_offset)) {
+ callsite_up =
+ std::make_unique<Declaration>(parent_decl_file, parent_entry->data);
+ }
+ } else {
+ // Its parent is a function, lookup global line table for callsite.
+ if (auto *entry = cii->m_global_line_table.FindEntryThatContains(
+ func_base + base_offset)) {
+ const FileSpec &callsite_file =
+ files.GetFileSpecAtIndex(entry->data.first);
+ callsite_up =
+ std::make_unique<Declaration>(callsite_file, entry->data.second);
+ }
+ }
+ }
+
+ // Get the inlined function name.
+ CVType inlinee_cvt = m_index->ipi().getType(inline_site.Inlinee);
+ std::string inlinee_name;
+ if (inlinee_cvt.kind() == LF_MFUNC_ID) {
+ MemberFuncIdRecord mfr;
+ cantFail(
+ TypeDeserializer::deserializeAs<MemberFuncIdRecord>(inlinee_cvt, mfr));
+ LazyRandomTypeCollection &types = m_index->tpi().typeCollection();
+ inlinee_name.append(std::string(types.getTypeName(mfr.ClassType)));
+ inlinee_name.append("::");
+ inlinee_name.append(mfr.getName().str());
+ } else if (inlinee_cvt.kind() == LF_FUNC_ID) {
+ FuncIdRecord fir;
+ cantFail(TypeDeserializer::deserializeAs<FuncIdRecord>(inlinee_cvt, fir));
+ TypeIndex parent_idx = fir.getParentScope();
+ if (!parent_idx.isNoneType()) {
+ LazyRandomTypeCollection &ids = m_index->ipi().typeCollection();
+ inlinee_name.append(std::string(ids.getTypeName(parent_idx)));
+ inlinee_name.append("::");
+ }
+ inlinee_name.append(fir.getName().str());
+ }
+ inline_site_sp->inline_function_info = std::make_shared<InlineFunctionInfo>(
+ inlinee_name.c_str(), llvm::StringRef(), decl_up.get(),
+ callsite_up.get());
+
+ m_inline_sites[opaque_uid] = inline_site_sp;
+}
+
+size_t SymbolFileNativePDB::ParseBlocksRecursive(Function &func) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ PdbCompilandSymId func_id = PdbSymUid(func.GetID()).asCompilandSym();
+ // After we iterate through inline sites inside the function, we already get
+ // all the info needed, removing from the map to save memory.
+ std::set<uint64_t> remove_uids;
+ auto parse_blocks = [&](SymbolKind kind, PdbCompilandSymId id) {
+ if (kind == S_GPROC32 || kind == S_LPROC32 || kind == S_BLOCK32 ||
+ kind == S_INLINESITE) {
+ GetOrCreateBlock(id);
+ if (kind == S_INLINESITE)
+ remove_uids.insert(toOpaqueUid(id));
+ return true;
+ }
+ return false;
+ };
+ size_t count = ParseSymbolArrayInScope(func_id, parse_blocks);
+ for (uint64_t uid : remove_uids) {
+ m_inline_sites.erase(uid);
+ }
+ return count;
+}
+
+size_t SymbolFileNativePDB::ParseSymbolArrayInScope(
+ PdbCompilandSymId parent_id,
+ llvm::function_ref<bool(SymbolKind, PdbCompilandSymId)> fn) {
+ CompilandIndexItem *cii = m_index->compilands().GetCompiland(parent_id.modi);
+ CVSymbolArray syms =
+ cii->m_debug_stream.getSymbolArrayForScope(parent_id.offset);
+
+ size_t count = 1;
+ for (auto iter = syms.begin(); iter != syms.end(); ++iter) {
+ PdbCompilandSymId child_id(parent_id.modi, iter.offset());
+ if (fn(iter->kind(), child_id))
+ ++count;
+ }
+
+ return count;
+}
+
+void SymbolFileNativePDB::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->GetNativePDBParser()->Dump(s);
+}
+
+void SymbolFileNativePDB::FindGlobalVariables(
+ ConstString name, const CompilerDeclContext &parent_decl_ctx,
+ uint32_t max_matches, VariableList &variables) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ using SymbolAndOffset = std::pair<uint32_t, llvm::codeview::CVSymbol>;
+
+ std::vector<SymbolAndOffset> results = m_index->globals().findRecordsByName(
+ name.GetStringRef(), m_index->symrecords());
+ for (const SymbolAndOffset &result : results) {
+ switch (result.second.kind()) {
+ case SymbolKind::S_GDATA32:
+ case SymbolKind::S_LDATA32:
+ case SymbolKind::S_GTHREAD32:
+ case SymbolKind::S_LTHREAD32:
+ case SymbolKind::S_CONSTANT: {
+ PdbGlobalSymId global(result.first, false);
+ if (VariableSP var = GetOrCreateGlobalVariable(global))
+ variables.AddVariable(var);
+ break;
+ }
+ default:
+ continue;
+ }
+ }
+}
+
+void SymbolFileNativePDB::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();
+ if (name_type_mask & eFunctionNameTypeFull)
+ name = lookup_info.GetName();
+
+ // For now we only support lookup by method name or full name.
+ if (!(name_type_mask & eFunctionNameTypeFull ||
+ name_type_mask & eFunctionNameTypeMethod))
+ return;
+
+ using SymbolAndOffset = std::pair<uint32_t, llvm::codeview::CVSymbol>;
+
+ std::vector<SymbolAndOffset> matches = m_index->globals().findRecordsByName(
+ name.GetStringRef(), m_index->symrecords());
+ for (const SymbolAndOffset &match : matches) {
+ if (match.second.kind() != S_PROCREF && match.second.kind() != S_LPROCREF)
+ continue;
+ ProcRefSym proc(match.second.kind());
+ cantFail(SymbolDeserializer::deserializeAs<ProcRefSym>(match.second, proc));
+
+ if (!IsValidRecord(proc))
+ continue;
+
+ CompilandIndexItem &cci =
+ m_index->compilands().GetOrCreateCompiland(proc.modi());
+ SymbolContext sc;
+
+ sc.comp_unit = GetOrCreateCompileUnit(cci).get();
+ PdbCompilandSymId func_id(proc.modi(), proc.SymOffset);
+ sc.function = GetOrCreateFunction(func_id, *sc.comp_unit).get();
+
+ sc_list.Append(sc);
+ }
+}
+
+void SymbolFileNativePDB::FindFunctions(const RegularExpression &regex,
+ bool include_inlines,
+ SymbolContextList &sc_list) {}
+
+void SymbolFileNativePDB::FindTypes(const lldb_private::TypeQuery &query,
+ lldb_private::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());
+
+ std::vector<TypeIndex> matches =
+ m_index->tpi().findRecordsByName(query.GetTypeBasename().GetStringRef());
+
+ for (TypeIndex type_idx : matches) {
+ TypeSP type_sp = GetOrCreateType(type_idx);
+ if (!type_sp)
+ continue;
+
+ // We resolved a type. Get the fully qualified name to ensure it matches.
+ ConstString name = type_sp->GetQualifiedName();
+ TypeQuery type_match(name.GetStringRef(), TypeQueryOptions::e_exact_match);
+ if (query.ContextMatches(type_match.GetContextRef())) {
+ results.InsertUnique(type_sp);
+ if (results.Done(query))
+ return;
+ }
+ }
+}
+
+void SymbolFileNativePDB::FindTypesByName(llvm::StringRef name,
+ uint32_t max_matches,
+ TypeMap &types) {
+
+ std::vector<TypeIndex> matches = m_index->tpi().findRecordsByName(name);
+ if (max_matches > 0 && max_matches < matches.size())
+ matches.resize(max_matches);
+
+ for (TypeIndex ti : matches) {
+ TypeSP type = GetOrCreateType(ti);
+ if (!type)
+ continue;
+
+ types.Insert(type);
+ }
+}
+
+size_t SymbolFileNativePDB::ParseTypes(CompileUnit &comp_unit) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ // Only do the full type scan the first time.
+ if (m_done_full_type_scan)
+ return 0;
+
+ const size_t old_count = GetTypeList().GetSize();
+ LazyRandomTypeCollection &types = m_index->tpi().typeCollection();
+
+ // First process the entire TPI stream.
+ for (auto ti = types.getFirst(); ti; ti = types.getNext(*ti)) {
+ TypeSP type = GetOrCreateType(*ti);
+ if (type)
+ (void)type->GetFullCompilerType();
+ }
+
+ // Next look for S_UDT records in the globals stream.
+ for (const uint32_t gid : m_index->globals().getGlobalsTable()) {
+ PdbGlobalSymId global{gid, false};
+ CVSymbol sym = m_index->ReadSymbolRecord(global);
+ if (sym.kind() != S_UDT)
+ continue;
+
+ UDTSym udt = llvm::cantFail(SymbolDeserializer::deserializeAs<UDTSym>(sym));
+ bool is_typedef = true;
+ if (IsTagRecord(PdbTypeSymId{udt.Type, false}, m_index->tpi())) {
+ CVType cvt = m_index->tpi().getType(udt.Type);
+ llvm::StringRef name = CVTagRecord::create(cvt).name();
+ if (name == udt.Name)
+ is_typedef = false;
+ }
+
+ if (is_typedef)
+ GetOrCreateTypedef(global);
+ }
+
+ const size_t new_count = GetTypeList().GetSize();
+
+ m_done_full_type_scan = true;
+
+ return new_count - old_count;
+}
+
+size_t
+SymbolFileNativePDB::ParseVariablesForCompileUnit(CompileUnit &comp_unit,
+ VariableList &variables) {
+ PdbSymUid sym_uid(comp_unit.GetID());
+ lldbassert(sym_uid.kind() == PdbSymUidKind::Compiland);
+ return 0;
+}
+
+VariableSP SymbolFileNativePDB::CreateLocalVariable(PdbCompilandSymId scope_id,
+ PdbCompilandSymId var_id,
+ bool is_param) {
+ ModuleSP module = GetObjectFile()->GetModule();
+ Block &block = GetOrCreateBlock(scope_id);
+ // Get function block.
+ Block *func_block = &block;
+ while (func_block->GetParent()) {
+ func_block = func_block->GetParent();
+ }
+ Address addr;
+ func_block->GetStartAddress(addr);
+ VariableInfo var_info =
+ GetVariableLocationInfo(*m_index, var_id, *func_block, module);
+ Function *func = func_block->CalculateSymbolContextFunction();
+ if (!func)
+ return nullptr;
+ // Use empty dwarf expr if optimized away so that it won't be filtered out
+ // when lookuping local variables in this scope.
+ if (!var_info.location.IsValid())
+ var_info.location = DWARFExpressionList(module, DWARFExpression(), nullptr);
+ var_info.location.SetFuncFileAddress(
+ func->GetAddressRange().GetBaseAddress().GetFileAddress());
+ CompilandIndexItem *cii = m_index->compilands().GetCompiland(var_id.modi);
+ CompUnitSP comp_unit_sp = GetOrCreateCompileUnit(*cii);
+ TypeSP type_sp = GetOrCreateType(var_info.type);
+ if (!type_sp)
+ return nullptr;
+ std::string name = var_info.name.str();
+ Declaration decl;
+ SymbolFileTypeSP sftype =
+ std::make_shared<SymbolFileType>(*this, type_sp->GetID());
+
+ is_param |= var_info.is_param;
+ ValueType var_scope =
+ is_param ? eValueTypeVariableArgument : eValueTypeVariableLocal;
+ bool external = false;
+ bool artificial = false;
+ bool location_is_constant_data = false;
+ bool static_member = false;
+ Variable::RangeList scope_ranges;
+ VariableSP var_sp = std::make_shared<Variable>(
+ toOpaqueUid(var_id), name.c_str(), name.c_str(), sftype, var_scope,
+ &block, scope_ranges, &decl, var_info.location, external, artificial,
+ location_is_constant_data, static_member);
+ if (!is_param) {
+ auto ts_or_err = GetTypeSystemForLanguage(comp_unit_sp->GetLanguage());
+ if (auto err = ts_or_err.takeError())
+ return nullptr;
+ auto ts = *ts_or_err;
+ if (!ts)
+ return nullptr;
+
+ ts->GetNativePDBParser()->GetOrCreateVariableDecl(scope_id, var_id);
+ }
+ m_local_variables[toOpaqueUid(var_id)] = var_sp;
+ return var_sp;
+}
+
+VariableSP SymbolFileNativePDB::GetOrCreateLocalVariable(
+ PdbCompilandSymId scope_id, PdbCompilandSymId var_id, bool is_param) {
+ auto iter = m_local_variables.find(toOpaqueUid(var_id));
+ if (iter != m_local_variables.end())
+ return iter->second;
+
+ return CreateLocalVariable(scope_id, var_id, is_param);
+}
+
+TypeSP SymbolFileNativePDB::CreateTypedef(PdbGlobalSymId id) {
+ CVSymbol sym = m_index->ReadSymbolRecord(id);
+ lldbassert(sym.kind() == SymbolKind::S_UDT);
+
+ UDTSym udt = llvm::cantFail(SymbolDeserializer::deserializeAs<UDTSym>(sym));
+
+ TypeSP target_type = GetOrCreateType(udt.Type);
+
+ auto ts_or_err = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
+ if (auto err = ts_or_err.takeError())
+ return nullptr;
+ auto ts = *ts_or_err;
+ if (!ts)
+ return nullptr;
+
+ ts->GetNativePDBParser()->GetOrCreateTypedefDecl(id);
+
+ Declaration decl;
+ return MakeType(
+ toOpaqueUid(id), ConstString(udt.Name), target_type->GetByteSize(nullptr),
+ nullptr, target_type->GetID(), lldb_private::Type::eEncodingIsTypedefUID,
+ decl, target_type->GetForwardCompilerType(),
+ lldb_private::Type::ResolveState::Forward);
+}
+
+TypeSP SymbolFileNativePDB::GetOrCreateTypedef(PdbGlobalSymId id) {
+ auto iter = m_types.find(toOpaqueUid(id));
+ if (iter != m_types.end())
+ return iter->second;
+
+ return CreateTypedef(id);
+}
+
+size_t SymbolFileNativePDB::ParseVariablesForBlock(PdbCompilandSymId block_id) {
+ Block &block = GetOrCreateBlock(block_id);
+
+ size_t count = 0;
+
+ CompilandIndexItem *cii = m_index->compilands().GetCompiland(block_id.modi);
+ CVSymbol sym = cii->m_debug_stream.readSymbolAtOffset(block_id.offset);
+ uint32_t params_remaining = 0;
+ switch (sym.kind()) {
+ case S_GPROC32:
+ case S_LPROC32: {
+ ProcSym proc(static_cast<SymbolRecordKind>(sym.kind()));
+ cantFail(SymbolDeserializer::deserializeAs<ProcSym>(sym, proc));
+ CVType signature = m_index->tpi().getType(proc.FunctionType);
+ if (signature.kind() == LF_PROCEDURE) {
+ ProcedureRecord sig;
+ if (llvm::Error e = TypeDeserializer::deserializeAs<ProcedureRecord>(
+ signature, sig)) {
+ llvm::consumeError(std::move(e));
+ return 0;
+ }
+ params_remaining = sig.getParameterCount();
+ } else if (signature.kind() == LF_MFUNCTION) {
+ MemberFunctionRecord sig;
+ if (llvm::Error e = TypeDeserializer::deserializeAs<MemberFunctionRecord>(
+ signature, sig)) {
+ llvm::consumeError(std::move(e));
+ return 0;
+ }
+ params_remaining = sig.getParameterCount();
+ } else
+ return 0;
+ break;
+ }
+ case S_BLOCK32:
+ break;
+ case S_INLINESITE:
+ break;
+ default:
+ lldbassert(false && "Symbol is not a block!");
+ return 0;
+ }
+
+ VariableListSP variables = block.GetBlockVariableList(false);
+ if (!variables) {
+ variables = std::make_shared<VariableList>();
+ block.SetVariableList(variables);
+ }
+
+ CVSymbolArray syms = limitSymbolArrayToScope(
+ cii->m_debug_stream.getSymbolArray(), block_id.offset);
+
+ // Skip the first record since it's a PROC32 or BLOCK32, and there's
+ // no point examining it since we know it's not a local variable.
+ syms.drop_front();
+ auto iter = syms.begin();
+ auto end = syms.end();
+
+ while (iter != end) {
+ uint32_t record_offset = iter.offset();
+ CVSymbol variable_cvs = *iter;
+ PdbCompilandSymId child_sym_id(block_id.modi, record_offset);
+ ++iter;
+
+ // If this is a block or inline site, recurse into its children and then
+ // skip it.
+ if (variable_cvs.kind() == S_BLOCK32 ||
+ variable_cvs.kind() == S_INLINESITE) {
+ uint32_t block_end = getScopeEndOffset(variable_cvs);
+ count += ParseVariablesForBlock(child_sym_id);
+ iter = syms.at(block_end);
+ continue;
+ }
+
+ bool is_param = params_remaining > 0;
+ VariableSP variable;
+ switch (variable_cvs.kind()) {
+ case S_REGREL32:
+ case S_REGISTER:
+ case S_LOCAL:
+ variable = GetOrCreateLocalVariable(block_id, child_sym_id, is_param);
+ if (is_param)
+ --params_remaining;
+ if (variable)
+ variables->AddVariableIfUnique(variable);
+ break;
+ default:
+ break;
+ }
+ }
+
+ // Pass false for set_children, since we call this recursively so that the
+ // children will call this for themselves.
+ block.SetDidParseVariables(true, false);
+
+ return count;
+}
+
+size_t SymbolFileNativePDB::ParseVariablesForContext(const SymbolContext &sc) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ lldbassert(sc.function || sc.comp_unit);
+
+ VariableListSP variables;
+ if (sc.block) {
+ PdbSymUid block_id(sc.block->GetID());
+
+ size_t count = ParseVariablesForBlock(block_id.asCompilandSym());
+ return count;
+ }
+
+ if (sc.function) {
+ PdbSymUid block_id(sc.function->GetID());
+
+ size_t count = ParseVariablesForBlock(block_id.asCompilandSym());
+ return count;
+ }
+
+ if (sc.comp_unit) {
+ variables = sc.comp_unit->GetVariableList(false);
+ if (!variables) {
+ variables = std::make_shared<VariableList>();
+ sc.comp_unit->SetVariableList(variables);
+ }
+ return ParseVariablesForCompileUnit(*sc.comp_unit, *variables);
+ }
+
+ llvm_unreachable("Unreachable!");
+}
+
+CompilerDecl SymbolFileNativePDB::GetDeclForUID(lldb::user_id_t uid) {
+ auto ts_or_err = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
+ if (auto err = ts_or_err.takeError())
+ return CompilerDecl();
+ auto ts = *ts_or_err;
+ if (!ts)
+ return {};
+
+ if (auto decl = ts->GetNativePDBParser()->GetOrCreateDeclForUid(uid))
+ return *decl;
+ return CompilerDecl();
+}
+
+CompilerDeclContext
+SymbolFileNativePDB::GetDeclContextForUID(lldb::user_id_t uid) {
+ auto ts_or_err = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
+ if (auto err = ts_or_err.takeError())
+ return {};
+ auto ts = *ts_or_err;
+ if (!ts)
+ return {};
+
+ PdbAstBuilder *ast_builder = ts->GetNativePDBParser();
+ clang::DeclContext *context =
+ ast_builder->GetOrCreateDeclContextForUid(PdbSymUid(uid));
+ if (!context)
+ return {};
+
+ return ast_builder->ToCompilerDeclContext(*context);
+}
+
+CompilerDeclContext
+SymbolFileNativePDB::GetDeclContextContainingUID(lldb::user_id_t uid) {
+ auto ts_or_err = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
+ if (auto err = ts_or_err.takeError())
+ return CompilerDeclContext();
+ auto ts = *ts_or_err;
+ if (!ts)
+ return {};
+
+ PdbAstBuilder *ast_builder = ts->GetNativePDBParser();
+ clang::DeclContext *context = ast_builder->GetParentDeclContext(PdbSymUid(uid));
+ if (!context)
+ return CompilerDeclContext();
+ return ast_builder->ToCompilerDeclContext(*context);
+}
+
+Type *SymbolFileNativePDB::ResolveTypeUID(lldb::user_id_t type_uid) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ auto iter = m_types.find(type_uid);
+ // lldb should not be passing us non-sensical type uids. the only way it
+ // could have a type uid in the first place is if we handed it out, in which
+ // case we should know about the type. However, that doesn't mean we've
+ // instantiated it yet. We can vend out a UID for a future type. So if the
+ // type doesn't exist, let's instantiate it now.
+ if (iter != m_types.end())
+ return &*iter->second;
+
+ PdbSymUid uid(type_uid);
+ lldbassert(uid.kind() == PdbSymUidKind::Type);
+ PdbTypeSymId type_id = uid.asTypeSym();
+ if (type_id.index.isNoneType())
+ return nullptr;
+
+ TypeSP type_sp = CreateAndCacheType(type_id);
+ if (!type_sp)
+ return nullptr;
+ return &*type_sp;
+}
+
+std::optional<SymbolFile::ArrayInfo>
+SymbolFileNativePDB::GetDynamicArrayInfoForUID(
+ lldb::user_id_t type_uid, const lldb_private::ExecutionContext *exe_ctx) {
+ return std::nullopt;
+}
+
+bool SymbolFileNativePDB::CompleteType(CompilerType &compiler_type) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ auto ts = compiler_type.GetTypeSystem();
+ auto clang_type_system = ts.dyn_cast_or_null<TypeSystemClang>();
+ if (!clang_type_system)
+ return false;
+
+ PdbAstBuilder *ast_builder =
+ static_cast<PdbAstBuilder *>(clang_type_system->GetNativePDBParser());
+ if (ast_builder &&
+ ast_builder->GetClangASTImporter().CanImport(compiler_type))
+ return ast_builder->GetClangASTImporter().CompleteType(compiler_type);
+ clang::QualType qt =
+ clang::QualType::getFromOpaquePtr(compiler_type.GetOpaqueQualType());
+
+ return ast_builder->CompleteType(qt);
+}
+
+void SymbolFileNativePDB::GetTypes(lldb_private::SymbolContextScope *sc_scope,
+ TypeClass type_mask,
+ lldb_private::TypeList &type_list) {}
+
+CompilerDeclContext SymbolFileNativePDB::FindNamespace(
+ ConstString name, const CompilerDeclContext &parent_decl_ctx, bool) {
+ return {};
+}
+
+llvm::Expected<lldb::TypeSystemSP>
+SymbolFileNativePDB::GetTypeSystemForLanguage(lldb::LanguageType 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;
+}
+
+uint64_t SymbolFileNativePDB::GetDebugInfoSize(bool load_all_debug_info) {
+ // PDB files are a separate file that contains all debug info.
+ return m_index->pdb().getFileSize();
+}
+
+void SymbolFileNativePDB::BuildParentMap() {
+ LazyRandomTypeCollection &types = m_index->tpi().typeCollection();
+
+ llvm::DenseMap<TypeIndex, TypeIndex> forward_to_full;
+ llvm::DenseMap<TypeIndex, TypeIndex> full_to_forward;
+
+ struct RecordIndices {
+ TypeIndex forward;
+ TypeIndex full;
+ };
+
+ llvm::StringMap<RecordIndices> record_indices;
+
+ for (auto ti = types.getFirst(); ti; ti = types.getNext(*ti)) {
+ CVType type = types.getType(*ti);
+ if (!IsTagRecord(type))
+ continue;
+
+ CVTagRecord tag = CVTagRecord::create(type);
+
+ RecordIndices &indices = record_indices[tag.asTag().getUniqueName()];
+ if (tag.asTag().isForwardRef())
+ indices.forward = *ti;
+ else
+ indices.full = *ti;
+
+ if (indices.full != TypeIndex::None() &&
+ indices.forward != TypeIndex::None()) {
+ forward_to_full[indices.forward] = indices.full;
+ full_to_forward[indices.full] = indices.forward;
+ }
+
+ // We're looking for LF_NESTTYPE records in the field list, so ignore
+ // forward references (no field list), and anything without a nested class
+ // (since there won't be any LF_NESTTYPE records).
+ if (tag.asTag().isForwardRef() || !tag.asTag().containsNestedClass())
+ continue;
+
+ struct ProcessTpiStream : public TypeVisitorCallbacks {
+ ProcessTpiStream(PdbIndex &index, TypeIndex parent,
+ const CVTagRecord &parent_cvt,
+ llvm::DenseMap<TypeIndex, TypeIndex> &parents)
+ : index(index), parents(parents), parent(parent),
+ parent_cvt(parent_cvt) {}
+
+ PdbIndex &index;
+ llvm::DenseMap<TypeIndex, TypeIndex> &parents;
+
+ unsigned unnamed_type_index = 1;
+ TypeIndex parent;
+ const CVTagRecord &parent_cvt;
+
+ llvm::Error visitKnownMember(CVMemberRecord &CVR,
+ NestedTypeRecord &Record) override {
+ std::string unnamed_type_name;
+ if (Record.Name.empty()) {
+ unnamed_type_name =
+ llvm::formatv("<unnamed-type-$S{0}>", unnamed_type_index).str();
+ Record.Name = unnamed_type_name;
+ ++unnamed_type_index;
+ }
+ std::optional<CVTagRecord> tag =
+ GetNestedTagDefinition(Record, parent_cvt, index.tpi());
+ if (!tag)
+ return llvm::ErrorSuccess();
+
+ parents[Record.Type] = parent;
+ return llvm::ErrorSuccess();
+ }
+ };
+
+ CVType field_list_cvt = m_index->tpi().getType(tag.asTag().FieldList);
+ ProcessTpiStream process(*m_index, *ti, tag, m_parent_types);
+ FieldListRecord field_list;
+ if (llvm::Error error = TypeDeserializer::deserializeAs<FieldListRecord>(
+ field_list_cvt, field_list))
+ llvm::consumeError(std::move(error));
+ if (llvm::Error error = visitMemberRecordStream(field_list.Data, process))
+ llvm::consumeError(std::move(error));
+ }
+
+ // Now that we know the forward -> full mapping of all type indices, we can
+ // re-write all the indices. At the end of this process, we want a mapping
+ // consisting of fwd -> full and full -> full for all child -> parent indices.
+ // We can re-write the values in place, but for the keys, we must save them
+ // off so that we don't modify the map in place while also iterating it.
+ std::vector<TypeIndex> full_keys;
+ std::vector<TypeIndex> fwd_keys;
+ for (auto &entry : m_parent_types) {
+ TypeIndex key = entry.first;
+ TypeIndex value = entry.second;
+
+ auto iter = forward_to_full.find(value);
+ if (iter != forward_to_full.end())
+ entry.second = iter->second;
+
+ iter = forward_to_full.find(key);
+ if (iter != forward_to_full.end())
+ fwd_keys.push_back(key);
+ else
+ full_keys.push_back(key);
+ }
+ for (TypeIndex fwd : fwd_keys) {
+ TypeIndex full = forward_to_full[fwd];
+ TypeIndex parent_idx = m_parent_types[fwd];
+ m_parent_types[full] = parent_idx;
+ }
+ for (TypeIndex full : full_keys) {
+ TypeIndex fwd = full_to_forward[full];
+ m_parent_types[fwd] = m_parent_types[full];
+ }
+}
+
+std::optional<PdbCompilandSymId>
+SymbolFileNativePDB::FindSymbolScope(PdbCompilandSymId id) {
+ CVSymbol sym = m_index->ReadSymbolRecord(id);
+ if (symbolOpensScope(sym.kind())) {
+ // If this exact symbol opens a scope, we can just directly access its
+ // parent.
+ id.offset = getScopeParentOffset(sym);
+ // Global symbols have parent offset of 0. Return std::nullopt to indicate
+ // this.
+ if (id.offset == 0)
+ return std::nullopt;
+ return id;
+ }
+
+ // Otherwise we need to start at the beginning and iterate forward until we
+ // reach (or pass) this particular symbol
+ CompilandIndexItem &cii = m_index->compilands().GetOrCreateCompiland(id.modi);
+ const CVSymbolArray &syms = cii.m_debug_stream.getSymbolArray();
+
+ auto begin = syms.begin();
+ auto end = syms.at(id.offset);
+ std::vector<PdbCompilandSymId> scope_stack;
+
+ while (begin != end) {
+ if (begin.offset() > id.offset) {
+ // We passed it. We couldn't even find this symbol record.
+ lldbassert(false && "Invalid compiland symbol id!");
+ return std::nullopt;
+ }
+
+ // We haven't found the symbol yet. Check if we need to open or close the
+ // scope stack.
+ if (symbolOpensScope(begin->kind())) {
+ // We can use the end offset of the scope to determine whether or not
+ // we can just outright skip this entire scope.
+ uint32_t scope_end = getScopeEndOffset(*begin);
+ if (scope_end < id.offset) {
+ begin = syms.at(scope_end);
+ } else {
+ // The symbol we're looking for is somewhere in this scope.
+ scope_stack.emplace_back(id.modi, begin.offset());
+ }
+ } else if (symbolEndsScope(begin->kind())) {
+ scope_stack.pop_back();
+ }
+ ++begin;
+ }
+ if (scope_stack.empty())
+ return std::nullopt;
+ // We have a match! Return the top of the stack
+ return scope_stack.back();
+}
+
+std::optional<llvm::codeview::TypeIndex>
+SymbolFileNativePDB::GetParentType(llvm::codeview::TypeIndex ti) {
+ auto parent_iter = m_parent_types.find(ti);
+ if (parent_iter == m_parent_types.end())
+ return std::nullopt;
+ return parent_iter->second;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
new file mode 100644
index 000000000000..669c44aa131e
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
@@ -0,0 +1,286 @@
+//===-- SymbolFileNativePDB.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_NATIVEPDB_SYMBOLFILENATIVEPDB_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_SYMBOLFILENATIVEPDB_H
+
+#include "lldb/Symbol/LineTable.h"
+#include "lldb/Symbol/SymbolFile.h"
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/DebugInfo/CodeView/CVRecord.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/PDB/PDBTypes.h"
+
+#include "CompileUnitIndex.h"
+#include "PdbIndex.h"
+#include "PdbAstBuilder.h"
+#include <optional>
+
+namespace clang {
+class TagDecl;
+}
+
+namespace llvm {
+namespace codeview {
+class ClassRecord;
+class EnumRecord;
+class ModifierRecord;
+class PointerRecord;
+struct UnionRecord;
+} // namespace codeview
+} // namespace llvm
+
+namespace lldb_private {
+
+namespace npdb {
+
+class SymbolFileNativePDB : public SymbolFileCommon {
+ friend class UdtRecordCompleter;
+
+ /// 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 void DebuggerInitialize(Debugger &debugger);
+
+ static llvm::StringRef GetPluginNameStatic() { return "native-pdb"; }
+
+ static llvm::StringRef GetPluginDescriptionStatic();
+
+ static SymbolFile *CreateInstance(lldb::ObjectFileSP objfile_sp);
+
+ // Constructors and Destructors
+ SymbolFileNativePDB(lldb::ObjectFileSP objfile_sp);
+
+ ~SymbolFileNativePDB() override;
+
+ uint32_t CalculateAbilities() override;
+
+ void InitializeObject() override;
+
+ uint64_t GetDebugInfoSize(bool load_all_debug_info = false) override;
+
+ // Compile Unit function calls
+
+ void
+ ParseDeclsForContext(lldb_private::CompilerDeclContext decl_ctx) override;
+
+ lldb::LanguageType
+ ParseLanguage(lldb_private::CompileUnit &comp_unit) override;
+
+ size_t ParseFunctions(lldb_private::CompileUnit &comp_unit) override;
+
+ bool ParseLineTable(lldb_private::CompileUnit &comp_unit) override;
+
+ bool ParseDebugMacros(lldb_private::CompileUnit &comp_unit) override;
+
+ bool ParseSupportFiles(lldb_private::CompileUnit &comp_unit,
+ SupportFileList &support_files) override;
+ size_t ParseTypes(lldb_private::CompileUnit &comp_unit) override;
+
+ bool ParseImportedModules(
+ const SymbolContext &sc,
+ std::vector<lldb_private::SourceModule> &imported_modules) override;
+
+ size_t ParseBlocksRecursive(Function &func) override;
+
+ void FindGlobalVariables(ConstString name,
+ const CompilerDeclContext &parent_decl_ctx,
+ uint32_t max_matches,
+ VariableList &variables) override;
+
+ size_t ParseVariablesForContext(const SymbolContext &sc) override;
+
+ void AddSymbols(Symtab &symtab) override;
+
+ CompilerDecl GetDeclForUID(lldb::user_id_t uid) override;
+ CompilerDeclContext GetDeclContextForUID(lldb::user_id_t uid) override;
+ CompilerDeclContext GetDeclContextContainingUID(lldb::user_id_t uid) override;
+ Type *ResolveTypeUID(lldb::user_id_t type_uid) override;
+ std::optional<ArrayInfo> GetDynamicArrayInfoForUID(
+ lldb::user_id_t type_uid,
+ const lldb_private::ExecutionContext *exe_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;
+
+ void GetTypes(SymbolContextScope *sc_scope, lldb::TypeClass type_mask,
+ TypeList &type_list) 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;
+
+ std::optional<PdbCompilandSymId> FindSymbolScope(PdbCompilandSymId id);
+
+ void FindTypes(const lldb_private::TypeQuery &match,
+ lldb_private::TypeResults &results) override;
+
+ llvm::Expected<lldb::TypeSystemSP>
+ GetTypeSystemForLanguage(lldb::LanguageType language) override;
+
+ CompilerDeclContext FindNamespace(ConstString name,
+ const CompilerDeclContext &parent_decl_ctx,
+ bool only_root_namespaces) override;
+
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+ llvm::pdb::PDBFile &GetPDBFile() { return m_index->pdb(); }
+ const llvm::pdb::PDBFile &GetPDBFile() const { return m_index->pdb(); }
+
+ PdbIndex &GetIndex() { return *m_index; };
+
+ void DumpClangAST(Stream &s) override;
+
+ std::optional<llvm::codeview::TypeIndex>
+ GetParentType(llvm::codeview::TypeIndex ti);
+
+private:
+ struct LineTableEntryComparator {
+ bool operator()(const lldb_private::LineTable::Entry &lhs,
+ const lldb_private::LineTable::Entry &rhs) const {
+ return lhs.file_addr < rhs.file_addr;
+ }
+ };
+
+ // From address range relative to function base to source line number.
+ using RangeSourceLineVector =
+ lldb_private::RangeDataVector<uint32_t, uint32_t, int32_t>;
+ // InlineSite contains information in a S_INLINESITE record.
+ struct InlineSite {
+ PdbCompilandSymId parent_id;
+ std::shared_ptr<InlineFunctionInfo> inline_function_info;
+ RangeSourceLineVector ranges;
+ std::vector<lldb_private::LineTable::Entry> line_entries;
+ InlineSite(PdbCompilandSymId parent_id) : parent_id(parent_id){};
+ };
+
+ void BuildParentMap();
+
+ uint32_t CalculateNumCompileUnits() override;
+
+ lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index) override;
+
+ void FindTypesByName(llvm::StringRef name, uint32_t max_matches,
+ TypeMap &types);
+
+ lldb::TypeSP CreateModifierType(PdbTypeSymId type_id,
+ const llvm::codeview::ModifierRecord &mr,
+ CompilerType ct);
+ lldb::TypeSP CreatePointerType(PdbTypeSymId type_id,
+ const llvm::codeview::PointerRecord &pr,
+ CompilerType ct);
+ lldb::TypeSP CreateSimpleType(llvm::codeview::TypeIndex ti, CompilerType ct);
+ lldb::TypeSP CreateTagType(PdbTypeSymId type_id,
+ const llvm::codeview::ClassRecord &cr,
+ CompilerType ct);
+ lldb::TypeSP CreateTagType(PdbTypeSymId type_id,
+ const llvm::codeview::EnumRecord &er,
+ CompilerType ct);
+ lldb::TypeSP CreateTagType(PdbTypeSymId type_id,
+ const llvm::codeview::UnionRecord &ur,
+ CompilerType ct);
+ lldb::TypeSP CreateArrayType(PdbTypeSymId type_id,
+ const llvm::codeview::ArrayRecord &ar,
+ CompilerType ct);
+ lldb::TypeSP CreateFunctionType(PdbTypeSymId type_id,
+ const llvm::codeview::MemberFunctionRecord &pr,
+ CompilerType ct);
+ lldb::TypeSP CreateProcedureType(PdbTypeSymId type_id,
+ const llvm::codeview::ProcedureRecord &pr,
+ CompilerType ct);
+ lldb::TypeSP CreateClassStructUnion(PdbTypeSymId type_id,
+ const llvm::codeview::TagRecord &record,
+ size_t size, CompilerType ct);
+
+ lldb::FunctionSP GetOrCreateFunction(PdbCompilandSymId func_id,
+ CompileUnit &comp_unit);
+ lldb::CompUnitSP GetOrCreateCompileUnit(const CompilandIndexItem &cci);
+ lldb::TypeSP GetOrCreateType(PdbTypeSymId type_id);
+ lldb::TypeSP GetOrCreateType(llvm::codeview::TypeIndex ti);
+ lldb::VariableSP GetOrCreateGlobalVariable(PdbGlobalSymId var_id);
+ Block &GetOrCreateBlock(PdbCompilandSymId block_id);
+ lldb::VariableSP GetOrCreateLocalVariable(PdbCompilandSymId scope_id,
+ PdbCompilandSymId var_id,
+ bool is_param);
+ lldb::TypeSP GetOrCreateTypedef(PdbGlobalSymId id);
+
+ lldb::FunctionSP CreateFunction(PdbCompilandSymId func_id,
+ CompileUnit &comp_unit);
+ Block &CreateBlock(PdbCompilandSymId block_id);
+ lldb::VariableSP CreateLocalVariable(PdbCompilandSymId scope_id,
+ PdbCompilandSymId var_id, bool is_param);
+ lldb::TypeSP CreateTypedef(PdbGlobalSymId id);
+ lldb::CompUnitSP CreateCompileUnit(const CompilandIndexItem &cci);
+ lldb::TypeSP CreateType(PdbTypeSymId type_id, CompilerType ct);
+ lldb::TypeSP CreateAndCacheType(PdbTypeSymId type_id);
+ lldb::VariableSP CreateGlobalVariable(PdbGlobalSymId var_id);
+ lldb::VariableSP CreateConstantSymbol(PdbGlobalSymId var_id,
+ const llvm::codeview::CVSymbol &cvs);
+ size_t ParseVariablesForCompileUnit(CompileUnit &comp_unit,
+ VariableList &variables);
+ size_t ParseVariablesForBlock(PdbCompilandSymId block_id);
+
+ llvm::Expected<uint32_t> GetFileIndex(const CompilandIndexItem &cii,
+ uint32_t file_id);
+
+ size_t ParseSymbolArrayInScope(
+ PdbCompilandSymId parent,
+ llvm::function_ref<bool(llvm::codeview::SymbolKind, PdbCompilandSymId)>
+ fn);
+
+ void ParseInlineSite(PdbCompilandSymId inline_site_id, Address func_addr);
+
+ llvm::BumpPtrAllocator m_allocator;
+
+ lldb::addr_t m_obj_load_address = 0;
+ bool m_done_full_type_scan = false;
+ // UID for anonymous union and anonymous struct as they don't have entities in
+ // pdb debug info.
+ lldb::user_id_t anonymous_id = LLDB_INVALID_UID - 1;
+
+ std::unique_ptr<llvm::pdb::PDBFile> m_file_up;
+ std::unique_ptr<PdbIndex> m_index;
+
+ llvm::DenseMap<lldb::user_id_t, lldb::VariableSP> m_global_vars;
+ llvm::DenseMap<lldb::user_id_t, lldb::VariableSP> m_local_variables;
+ llvm::DenseMap<lldb::user_id_t, lldb::BlockSP> m_blocks;
+ llvm::DenseMap<lldb::user_id_t, lldb::FunctionSP> m_functions;
+ llvm::DenseMap<lldb::user_id_t, lldb::CompUnitSP> m_compilands;
+ llvm::DenseMap<lldb::user_id_t, lldb::TypeSP> m_types;
+ llvm::DenseMap<lldb::user_id_t, std::shared_ptr<InlineSite>> m_inline_sites;
+ llvm::DenseMap<llvm::codeview::TypeIndex, llvm::codeview::TypeIndex>
+ m_parent_types;
+};
+
+} // namespace npdb
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_SYMBOLFILENATIVEPDB_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
new file mode 100644
index 000000000000..17c5f6118603
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
@@ -0,0 +1,501 @@
+#include "UdtRecordCompleter.h"
+
+#include "PdbAstBuilder.h"
+#include "PdbIndex.h"
+#include "PdbSymUid.h"
+#include "PdbUtil.h"
+
+#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
+#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h"
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "SymbolFileNativePDB.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/DebugInfo/PDB/PDBTypes.h"
+#include <optional>
+
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::npdb;
+
+using Error = llvm::Error;
+
+UdtRecordCompleter::UdtRecordCompleter(
+ PdbTypeSymId id, CompilerType &derived_ct, clang::TagDecl &tag_decl,
+ PdbAstBuilder &ast_builder, PdbIndex &index,
+ llvm::DenseMap<clang::Decl *, DeclStatus> &decl_to_status,
+ llvm::DenseMap<lldb::opaque_compiler_type_t,
+ llvm::SmallSet<std::pair<llvm::StringRef, CompilerType>, 8>>
+ &cxx_record_map)
+ : m_id(id), m_derived_ct(derived_ct), m_tag_decl(tag_decl),
+ m_ast_builder(ast_builder), m_index(index),
+ m_decl_to_status(decl_to_status), m_cxx_record_map(cxx_record_map) {
+ CVType cvt = m_index.tpi().getType(m_id.index);
+ switch (cvt.kind()) {
+ case LF_ENUM:
+ m_cvr.er.Options = ClassOptions::None;
+ llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, m_cvr.er));
+ break;
+ case LF_UNION:
+ m_cvr.ur.Options = ClassOptions::None;
+ llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, m_cvr.ur));
+ m_layout.bit_size = m_cvr.ur.getSize() * 8;
+ m_record.record.kind = Member::Union;
+ break;
+ case LF_CLASS:
+ case LF_STRUCTURE:
+ m_cvr.cr.Options = ClassOptions::None;
+ llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, m_cvr.cr));
+ m_layout.bit_size = m_cvr.cr.getSize() * 8;
+ m_record.record.kind = Member::Struct;
+ break;
+ default:
+ llvm_unreachable("unreachable!");
+ }
+}
+
+clang::QualType UdtRecordCompleter::AddBaseClassForTypeIndex(
+ llvm::codeview::TypeIndex ti, llvm::codeview::MemberAccess access,
+ std::optional<uint64_t> vtable_idx) {
+ PdbTypeSymId type_id(ti);
+ clang::QualType qt = m_ast_builder.GetOrCreateType(type_id);
+
+ CVType udt_cvt = m_index.tpi().getType(ti);
+
+ std::unique_ptr<clang::CXXBaseSpecifier> base_spec =
+ m_ast_builder.clang().CreateBaseClassSpecifier(
+ qt.getAsOpaquePtr(), TranslateMemberAccess(access),
+ vtable_idx.has_value(), udt_cvt.kind() == LF_CLASS);
+ if (!base_spec)
+ return {};
+
+ m_bases.push_back(
+ std::make_pair(vtable_idx.value_or(0), std::move(base_spec)));
+
+ return qt;
+}
+
+void UdtRecordCompleter::AddMethod(llvm::StringRef name, TypeIndex type_idx,
+ MemberAccess access, MethodOptions options,
+ MemberAttributes attrs) {
+ clang::QualType method_qt =
+ m_ast_builder.GetOrCreateType(PdbTypeSymId(type_idx));
+ if (method_qt.isNull())
+ return;
+ CompilerType method_ct = m_ast_builder.ToCompilerType(method_qt);
+ TypeSystemClang::RequireCompleteType(method_ct);
+ lldb::opaque_compiler_type_t derived_opaque_ty =
+ m_derived_ct.GetOpaqueQualType();
+ auto iter = m_cxx_record_map.find(derived_opaque_ty);
+ if (iter != m_cxx_record_map.end()) {
+ if (iter->getSecond().contains({name, method_ct})) {
+ return;
+ }
+ }
+
+ lldb::AccessType access_type = TranslateMemberAccess(access);
+ bool is_artificial = (options & MethodOptions::CompilerGenerated) ==
+ MethodOptions::CompilerGenerated;
+ m_ast_builder.clang().AddMethodToCXXRecordType(
+ derived_opaque_ty, name.data(), nullptr, method_ct,
+ access_type, attrs.isVirtual(), attrs.isStatic(), false, false, false,
+ is_artificial);
+
+ m_cxx_record_map[derived_opaque_ty].insert({name, method_ct});
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+ BaseClassRecord &base) {
+ clang::QualType base_qt =
+ AddBaseClassForTypeIndex(base.Type, base.getAccess());
+
+ if (base_qt.isNull())
+ return llvm::Error::success();
+ auto decl =
+ m_ast_builder.clang().GetAsCXXRecordDecl(base_qt.getAsOpaquePtr());
+ lldbassert(decl);
+
+ auto offset = clang::CharUnits::fromQuantity(base.getBaseOffset());
+ m_layout.base_offsets.insert(std::make_pair(decl, offset));
+
+ return llvm::Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+ VirtualBaseClassRecord &base) {
+ AddBaseClassForTypeIndex(base.BaseType, base.getAccess(), base.VTableIndex);
+
+ return Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+ ListContinuationRecord &cont) {
+ return Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+ VFPtrRecord &vfptr) {
+ return Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(
+ CVMemberRecord &cvr, StaticDataMemberRecord &static_data_member) {
+ clang::QualType member_type =
+ m_ast_builder.GetOrCreateType(PdbTypeSymId(static_data_member.Type));
+ if (member_type.isNull())
+ return llvm::Error::success();
+
+ CompilerType member_ct = m_ast_builder.ToCompilerType(member_type);
+
+ lldb::AccessType access =
+ TranslateMemberAccess(static_data_member.getAccess());
+ auto decl = TypeSystemClang::AddVariableToRecordType(
+ m_derived_ct, static_data_member.Name, member_ct, access);
+
+ // Static constant members may be a const[expr] declaration.
+ // Query the symbol's value as the variable initializer if valid.
+ if (member_ct.IsConst() && member_ct.IsCompleteType()) {
+ std::string qual_name = decl->getQualifiedNameAsString();
+
+ auto results =
+ m_index.globals().findRecordsByName(qual_name, m_index.symrecords());
+
+ for (const auto &result : results) {
+ if (result.second.kind() == SymbolKind::S_CONSTANT) {
+ ConstantSym constant(SymbolRecordKind::ConstantSym);
+ cantFail(SymbolDeserializer::deserializeAs<ConstantSym>(result.second,
+ constant));
+
+ clang::QualType qual_type = decl->getType();
+ unsigned type_width = decl->getASTContext().getIntWidth(qual_type);
+ unsigned constant_width = constant.Value.getBitWidth();
+
+ if (qual_type->isIntegralOrEnumerationType()) {
+ if (type_width >= constant_width) {
+ TypeSystemClang::SetIntegerInitializerForVariable(
+ decl, constant.Value.extOrTrunc(type_width));
+ } else {
+ LLDB_LOG(GetLog(LLDBLog::AST),
+ "Class '{0}' has a member '{1}' of type '{2}' ({3} bits) "
+ "which resolves to a wider constant value ({4} bits). "
+ "Ignoring constant.",
+ m_derived_ct.GetTypeName(), static_data_member.Name,
+ member_ct.GetTypeName(), type_width, constant_width);
+ }
+ } else {
+ lldb::BasicType basic_type_enum = member_ct.GetBasicTypeEnumeration();
+ switch (basic_type_enum) {
+ case lldb::eBasicTypeFloat:
+ case lldb::eBasicTypeDouble:
+ case lldb::eBasicTypeLongDouble:
+ if (type_width == constant_width) {
+ TypeSystemClang::SetFloatingInitializerForVariable(
+ decl, basic_type_enum == lldb::eBasicTypeFloat
+ ? llvm::APFloat(constant.Value.bitsToFloat())
+ : llvm::APFloat(constant.Value.bitsToDouble()));
+ decl->setConstexpr(true);
+ } else {
+ LLDB_LOG(
+ GetLog(LLDBLog::AST),
+ "Class '{0}' has a member '{1}' of type '{2}' ({3} bits) "
+ "which resolves to a constant value of mismatched width "
+ "({4} bits). Ignoring constant.",
+ m_derived_ct.GetTypeName(), static_data_member.Name,
+ member_ct.GetTypeName(), type_width, constant_width);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ // FIXME: Add a PdbSymUid namespace for field list members and update
+ // the m_uid_to_decl map with this decl.
+ return Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+ NestedTypeRecord &nested) {
+ return Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+ DataMemberRecord &data_member) {
+
+ uint64_t offset = data_member.FieldOffset * 8;
+ uint32_t bitfield_width = 0;
+
+ TypeIndex ti(data_member.Type);
+ if (!ti.isSimple()) {
+ CVType cvt = m_index.tpi().getType(ti);
+ if (cvt.kind() == LF_BITFIELD) {
+ BitFieldRecord bfr;
+ llvm::cantFail(TypeDeserializer::deserializeAs<BitFieldRecord>(cvt, bfr));
+ offset += bfr.BitOffset;
+ bitfield_width = bfr.BitSize;
+ ti = bfr.Type;
+ }
+ }
+
+ clang::QualType member_qt = m_ast_builder.GetOrCreateType(PdbTypeSymId(ti));
+ if (member_qt.isNull())
+ return Error::success();
+ TypeSystemClang::RequireCompleteType(m_ast_builder.ToCompilerType(member_qt));
+ lldb::AccessType access = TranslateMemberAccess(data_member.getAccess());
+ size_t field_size =
+ bitfield_width ? bitfield_width : GetSizeOfType(ti, m_index.tpi()) * 8;
+ if (field_size == 0)
+ return Error::success();
+ m_record.CollectMember(data_member.Name, offset, field_size, member_qt, access,
+ bitfield_width);
+ return Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+ OneMethodRecord &one_method) {
+ AddMethod(one_method.Name, one_method.Type, one_method.getAccess(),
+ one_method.getOptions(), one_method.Attrs);
+
+ return Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+ OverloadedMethodRecord &overloaded) {
+ TypeIndex method_list_idx = overloaded.MethodList;
+
+ CVType method_list_type = m_index.tpi().getType(method_list_idx);
+ assert(method_list_type.kind() == LF_METHODLIST);
+
+ MethodOverloadListRecord method_list;
+ llvm::cantFail(TypeDeserializer::deserializeAs<MethodOverloadListRecord>(
+ method_list_type, method_list));
+
+ for (const OneMethodRecord &method : method_list.Methods)
+ AddMethod(overloaded.Name, method.Type, method.getAccess(),
+ method.getOptions(), method.Attrs);
+
+ return Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+ EnumeratorRecord &enumerator) {
+ Declaration decl;
+ llvm::StringRef name = DropNameScope(enumerator.getName());
+
+ m_ast_builder.clang().AddEnumerationValueToEnumerationType(
+ m_derived_ct, decl, name.str().c_str(), enumerator.Value);
+ return Error::success();
+}
+
+void UdtRecordCompleter::complete() {
+ // Ensure the correct order for virtual bases.
+ llvm::stable_sort(m_bases, llvm::less_first());
+
+ std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> bases;
+ bases.reserve(m_bases.size());
+ for (auto &ib : m_bases)
+ bases.push_back(std::move(ib.second));
+
+ TypeSystemClang &clang = m_ast_builder.clang();
+ // 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(
+ clang.GetType(type_source_info->getType()));
+ }
+ }
+
+ clang.TransferBaseClasses(m_derived_ct.GetOpaqueQualType(), std::move(bases));
+
+ clang.AddMethodOverridesForCXXRecordType(m_derived_ct.GetOpaqueQualType());
+ FinishRecord();
+ TypeSystemClang::BuildIndirectFields(m_derived_ct);
+ TypeSystemClang::CompleteTagDeclarationDefinition(m_derived_ct);
+
+ if (auto *record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(&m_tag_decl)) {
+ m_ast_builder.GetClangASTImporter().SetRecordLayout(record_decl, m_layout);
+ }
+}
+
+uint64_t
+UdtRecordCompleter::AddMember(TypeSystemClang &clang, Member *field,
+ uint64_t bit_offset, CompilerType parent_ct,
+ ClangASTImporter::LayoutInfo &parent_layout,
+ clang::DeclContext *parent_decl_ctx) {
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ clang.GetSymbolFile()->GetBackingSymbolFile());
+ clang::FieldDecl *field_decl = nullptr;
+ uint64_t bit_size = 0;
+ switch (field->kind) {
+ case Member::Field: {
+ field_decl = TypeSystemClang::AddFieldToRecordType(
+ parent_ct, field->name, m_ast_builder.ToCompilerType(field->qt),
+ field->access, field->bitfield_width);
+ bit_size = field->bit_size;
+ break;
+ };
+ case Member::Struct:
+ case Member::Union: {
+ clang::TagTypeKind kind = field->kind == Member::Struct
+ ? clang::TagTypeKind::Struct
+ : clang::TagTypeKind::Union;
+ ClangASTMetadata metadata;
+ metadata.SetUserID(pdb->anonymous_id);
+ metadata.SetIsDynamicCXXType(false);
+ CompilerType record_ct = clang.CreateRecordType(
+ parent_decl_ctx, OptionalClangModuleID(), lldb::eAccessPublic, "",
+ llvm::to_underlying(kind), lldb::eLanguageTypeC_plus_plus, &metadata);
+ TypeSystemClang::StartTagDeclarationDefinition(record_ct);
+ ClangASTImporter::LayoutInfo layout;
+ clang::DeclContext *decl_ctx = clang.GetDeclContextForType(record_ct);
+ for (const auto &member : field->fields) {
+ uint64_t member_offset = field->kind == Member::Struct
+ ? member->bit_offset - field->base_offset
+ : 0;
+ uint64_t member_bit_size = AddMember(clang, member.get(), member_offset,
+ record_ct, layout, decl_ctx);
+ if (field->kind == Member::Struct)
+ bit_size = std::max(bit_size, member_offset + member_bit_size);
+ else
+ bit_size = std::max(bit_size, member_bit_size);
+ }
+ layout.bit_size = bit_size;
+ TypeSystemClang::CompleteTagDeclarationDefinition(record_ct);
+ clang::RecordDecl *record_decl = clang.GetAsRecordDecl(record_ct);
+ m_ast_builder.GetClangASTImporter().SetRecordLayout(record_decl, layout);
+ field_decl = TypeSystemClang::AddFieldToRecordType(
+ parent_ct, "", record_ct, lldb::eAccessPublic, 0);
+ // Mark this record decl as completed.
+ DeclStatus status;
+ status.resolved = true;
+ status.uid = pdb->anonymous_id--;
+ m_decl_to_status.insert({record_decl, status});
+ break;
+ };
+ }
+ // FIXME: Add a PdbSymUid namespace for field list members and update
+ // the m_uid_to_decl map with this decl.
+ parent_layout.field_offsets.insert({field_decl, bit_offset});
+ return bit_size;
+}
+
+void UdtRecordCompleter::FinishRecord() {
+ TypeSystemClang &clang = m_ast_builder.clang();
+ clang::DeclContext *decl_ctx =
+ m_ast_builder.GetOrCreateDeclContextForUid(m_id);
+ m_record.ConstructRecord();
+ // Maybe we should check the construsted record size with the size in pdb. If
+ // they mismatch, it might be pdb has fields info missing.
+ for (const auto &field : m_record.record.fields) {
+ AddMember(clang, field.get(), field->bit_offset, m_derived_ct, m_layout,
+ decl_ctx);
+ }
+}
+
+void UdtRecordCompleter::Record::CollectMember(
+ llvm::StringRef name, uint64_t offset, uint64_t field_size,
+ clang::QualType qt, lldb::AccessType access, uint64_t bitfield_width) {
+ fields_map[offset].push_back(std::make_unique<Member>(
+ name, offset, field_size, qt, access, bitfield_width));
+ if (start_offset > offset)
+ start_offset = offset;
+}
+
+void UdtRecordCompleter::Record::ConstructRecord() {
+ // For anonymous unions in a struct, msvc generated pdb doesn't have the
+ // entity for that union. So, we need to construct anonymous union and struct
+ // based on field offsets. The final AST is likely not matching the exact
+ // original AST, but the memory layout is preseved.
+ // After we collecting all fields in visitKnownMember, we have all fields in
+ // increasing offset order in m_fields. Since we are iterating in increase
+ // offset order, if the current offset is equal to m_start_offset, we insert
+ // it as direct field of top level record. If the current offset is greater
+ // than m_start_offset, we should be able to find a field in end_offset_map
+ // whose end offset is less than or equal to current offset. (if not, it might
+ // be missing field info. We will ignore the field in this case. e.g. Field A
+ // starts at 0 with size 4 bytes, and Field B starts at 2 with size 4 bytes.
+ // Normally, there must be something which ends at/before 2.) Then we will
+ // append current field to the end of parent record. If parent is struct, we
+ // can just grow it. If parent is a field, it's a field inside an union. We
+ // convert it into an anonymous struct containing old field and new field.
+
+ // The end offset to a vector of field/struct that ends at the offset.
+ std::map<uint64_t, std::vector<Member *>> end_offset_map;
+ for (auto &pair : fields_map) {
+ uint64_t offset = pair.first;
+ auto &fields = pair.second;
+ lldbassert(offset >= start_offset);
+ Member *parent = &record;
+ if (offset > start_offset) {
+ // Find the field with largest end offset that is <= offset. If it's less
+ // than offset, it indicates there are padding bytes between end offset
+ // and offset.
+ lldbassert(!end_offset_map.empty());
+ auto iter = end_offset_map.lower_bound(offset);
+ if (iter == end_offset_map.end())
+ --iter;
+ else if (iter->first > offset) {
+ if (iter == end_offset_map.begin())
+ continue;
+ --iter;
+ }
+ if (iter->second.empty())
+ continue;
+ parent = iter->second.back();
+ iter->second.pop_back();
+ }
+ // If it's a field, then the field is inside a union, so we can safely
+ // increase its size by converting it to a struct to hold multiple fields.
+ if (parent->kind == Member::Field)
+ parent->ConvertToStruct();
+
+ if (fields.size() == 1) {
+ uint64_t end_offset = offset + fields.back()->bit_size;
+ parent->fields.push_back(std::move(fields.back()));
+ if (parent->kind == Member::Struct) {
+ end_offset_map[end_offset].push_back(parent);
+ } else {
+ lldbassert(parent == &record &&
+ "If parent is union, it must be the top level record.");
+ end_offset_map[end_offset].push_back(parent->fields.back().get());
+ }
+ } else {
+ if (parent->kind == Member::Struct) {
+ parent->fields.push_back(std::make_unique<Member>(Member::Union));
+ parent = parent->fields.back().get();
+ parent->bit_offset = offset;
+ } else {
+ lldbassert(parent == &record &&
+ "If parent is union, it must be the top level record.");
+ }
+ for (auto &field : fields) {
+ int64_t bit_size = field->bit_size;
+ parent->fields.push_back(std::move(field));
+ end_offset_map[offset + bit_size].push_back(
+ parent->fields.back().get());
+ }
+ }
+ }
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h
new file mode 100644
index 000000000000..e6e91d0f2c3e
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h
@@ -0,0 +1,146 @@
+//===-- UdtRecordCompleter.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_NATIVEPDB_UDTRECORDCOMPLETER_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_UDTRECORDCOMPLETER_H
+
+#include "PdbAstBuilder.h"
+#include "PdbSymUid.h"
+#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
+#include "llvm/DebugInfo/CodeView/CVRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
+#include <optional>
+
+namespace clang {
+class CXXBaseSpecifier;
+class QualType;
+class TagDecl;
+} // namespace clang
+
+namespace llvm {
+namespace pdb {
+class TpiStream;
+class GlobalsStream;
+}
+} // namespace llvm
+
+namespace lldb_private {
+class Type;
+class CompilerType;
+namespace npdb {
+class PdbAstBuilder;
+class PdbIndex;
+
+class UdtRecordCompleter : public llvm::codeview::TypeVisitorCallbacks {
+ using IndexedBase =
+ std::pair<uint64_t, std::unique_ptr<clang::CXXBaseSpecifier>>;
+
+ union UdtTagRecord {
+ UdtTagRecord() {}
+ llvm::codeview::UnionRecord ur;
+ llvm::codeview::ClassRecord cr;
+ llvm::codeview::EnumRecord er;
+ } m_cvr;
+
+ PdbTypeSymId m_id;
+ CompilerType &m_derived_ct;
+ clang::TagDecl &m_tag_decl;
+ PdbAstBuilder &m_ast_builder;
+ PdbIndex &m_index;
+ std::vector<IndexedBase> m_bases;
+ ClangASTImporter::LayoutInfo m_layout;
+ llvm::DenseMap<clang::Decl *, DeclStatus> &m_decl_to_status;
+ llvm::DenseMap<lldb::opaque_compiler_type_t,
+ llvm::SmallSet<std::pair<llvm::StringRef, CompilerType>, 8>>
+ &m_cxx_record_map;
+
+public:
+ UdtRecordCompleter(
+ PdbTypeSymId id, CompilerType &derived_ct, clang::TagDecl &tag_decl,
+ PdbAstBuilder &ast_builder, PdbIndex &index,
+ llvm::DenseMap<clang::Decl *, DeclStatus> &decl_to_status,
+ llvm::DenseMap<lldb::opaque_compiler_type_t,
+ llvm::SmallSet<std::pair<llvm::StringRef, CompilerType>,
+ 8>> &cxx_record_map);
+
+#define MEMBER_RECORD(EnumName, EnumVal, Name) \
+ llvm::Error visitKnownMember(llvm::codeview::CVMemberRecord &CVR, \
+ llvm::codeview::Name##Record &Record) override;
+#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
+
+ struct Member;
+ using MemberUP = std::unique_ptr<Member>;
+
+ struct Member {
+ enum Kind { Field, Struct, Union } kind;
+ // Following are only used for field.
+ llvm::StringRef name;
+ uint64_t bit_offset;
+ uint64_t bit_size;
+ clang::QualType qt;
+ lldb::AccessType access;
+ uint32_t bitfield_width;
+ // Following are Only used for struct or union.
+ uint64_t base_offset;
+ llvm::SmallVector<MemberUP, 1> fields;
+
+ Member() = default;
+ Member(Kind kind)
+ : kind(kind), name(), bit_offset(0), bit_size(0), qt(),
+ access(lldb::eAccessPublic), bitfield_width(0), base_offset(0) {}
+ Member(llvm::StringRef name, uint64_t bit_offset, uint64_t bit_size,
+ clang::QualType qt, lldb::AccessType access, uint32_t bitfield_width)
+ : kind(Field), name(name), bit_offset(bit_offset), bit_size(bit_size),
+ qt(qt), access(access), bitfield_width(bitfield_width),
+ base_offset(0) {}
+ void ConvertToStruct() {
+ kind = Struct;
+ base_offset = bit_offset;
+ fields.push_back(std::make_unique<Member>(name, bit_offset, bit_size, qt,
+ access, bitfield_width));
+ name = llvm::StringRef();
+ qt = clang::QualType();
+ access = lldb::eAccessPublic;
+ bit_offset = bit_size = bitfield_width = 0;
+ }
+ };
+
+ struct Record {
+ // Top level record.
+ Member record;
+ uint64_t start_offset = UINT64_MAX;
+ std::map<uint64_t, llvm::SmallVector<MemberUP, 1>> fields_map;
+ void CollectMember(llvm::StringRef name, uint64_t offset,
+ uint64_t field_size, clang::QualType qt,
+ lldb::AccessType access, uint64_t bitfield_width);
+ void ConstructRecord();
+ };
+ void complete();
+
+private:
+ Record m_record;
+ clang::QualType AddBaseClassForTypeIndex(
+ llvm::codeview::TypeIndex ti, llvm::codeview::MemberAccess access,
+ std::optional<uint64_t> vtable_idx = std::optional<uint64_t>());
+ void AddMethod(llvm::StringRef name, llvm::codeview::TypeIndex type_idx,
+ llvm::codeview::MemberAccess access,
+ llvm::codeview::MethodOptions options,
+ llvm::codeview::MemberAttributes attrs);
+ void FinishRecord();
+ uint64_t AddMember(TypeSystemClang &clang, Member *field, uint64_t bit_offset,
+ CompilerType parent_ct,
+ ClangASTImporter::LayoutInfo &parent_layout,
+ clang::DeclContext *decl_ctx);
+};
+
+} // namespace npdb
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_UDTRECORDCOMPLETER_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp
new file mode 100644
index 000000000000..d656ca3facf7
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp
@@ -0,0 +1,1455 @@
+//===-- PDBASTParser.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 "PDBASTParser.h"
+
+#include "SymbolFilePDB.h"
+
+#include "clang/AST/CharUnits.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+
+#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h"
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "lldb/Core/Declaration.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Symbol/TypeMap.h"
+#include "lldb/Symbol/TypeSystem.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h"
+#include "llvm/DebugInfo/PDB/IPDBLineNumber.h"
+#include "llvm/DebugInfo/PDB/IPDBSourceFile.h"
+#include "llvm/DebugInfo/PDB/PDBSymbol.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
+
+#include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h"
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace llvm::pdb;
+
+static int TranslateUdtKind(PDB_UdtType pdb_kind) {
+ switch (pdb_kind) {
+ case PDB_UdtType::Class:
+ return llvm::to_underlying(clang::TagTypeKind::Class);
+ case PDB_UdtType::Struct:
+ return llvm::to_underlying(clang::TagTypeKind::Struct);
+ case PDB_UdtType::Union:
+ return llvm::to_underlying(clang::TagTypeKind::Union);
+ case PDB_UdtType::Interface:
+ return llvm::to_underlying(clang::TagTypeKind::Interface);
+ }
+ llvm_unreachable("unsuported PDB UDT type");
+}
+
+static lldb::Encoding TranslateBuiltinEncoding(PDB_BuiltinType type) {
+ switch (type) {
+ case PDB_BuiltinType::Float:
+ return lldb::eEncodingIEEE754;
+ case PDB_BuiltinType::Int:
+ case PDB_BuiltinType::Long:
+ case PDB_BuiltinType::Char:
+ return lldb::eEncodingSint;
+ case PDB_BuiltinType::Bool:
+ case PDB_BuiltinType::Char16:
+ case PDB_BuiltinType::Char32:
+ case PDB_BuiltinType::UInt:
+ case PDB_BuiltinType::ULong:
+ case PDB_BuiltinType::HResult:
+ case PDB_BuiltinType::WCharT:
+ return lldb::eEncodingUint;
+ default:
+ return lldb::eEncodingInvalid;
+ }
+}
+
+static lldb::Encoding TranslateEnumEncoding(PDB_VariantType type) {
+ switch (type) {
+ case PDB_VariantType::Int8:
+ case PDB_VariantType::Int16:
+ case PDB_VariantType::Int32:
+ case PDB_VariantType::Int64:
+ return lldb::eEncodingSint;
+
+ case PDB_VariantType::UInt8:
+ case PDB_VariantType::UInt16:
+ case PDB_VariantType::UInt32:
+ case PDB_VariantType::UInt64:
+ return lldb::eEncodingUint;
+
+ default:
+ break;
+ }
+
+ return lldb::eEncodingSint;
+}
+
+static CompilerType
+GetBuiltinTypeForPDBEncodingAndBitSize(TypeSystemClang &clang_ast,
+ const PDBSymbolTypeBuiltin &pdb_type,
+ Encoding encoding, uint32_t width) {
+ clang::ASTContext &ast = clang_ast.getASTContext();
+
+ switch (pdb_type.getBuiltinType()) {
+ default:
+ break;
+ case PDB_BuiltinType::None:
+ return CompilerType();
+ case PDB_BuiltinType::Void:
+ return clang_ast.GetBasicType(eBasicTypeVoid);
+ case PDB_BuiltinType::Char:
+ return clang_ast.GetBasicType(eBasicTypeChar);
+ case PDB_BuiltinType::Bool:
+ return clang_ast.GetBasicType(eBasicTypeBool);
+ case PDB_BuiltinType::Long:
+ if (width == ast.getTypeSize(ast.LongTy))
+ return CompilerType(clang_ast.weak_from_this(),
+ ast.LongTy.getAsOpaquePtr());
+ if (width == ast.getTypeSize(ast.LongLongTy))
+ return CompilerType(clang_ast.weak_from_this(),
+ ast.LongLongTy.getAsOpaquePtr());
+ break;
+ case PDB_BuiltinType::ULong:
+ if (width == ast.getTypeSize(ast.UnsignedLongTy))
+ return CompilerType(clang_ast.weak_from_this(),
+ ast.UnsignedLongTy.getAsOpaquePtr());
+ if (width == ast.getTypeSize(ast.UnsignedLongLongTy))
+ return CompilerType(clang_ast.weak_from_this(),
+ ast.UnsignedLongLongTy.getAsOpaquePtr());
+ break;
+ case PDB_BuiltinType::WCharT:
+ if (width == ast.getTypeSize(ast.WCharTy))
+ return CompilerType(clang_ast.weak_from_this(),
+ ast.WCharTy.getAsOpaquePtr());
+ break;
+ case PDB_BuiltinType::Char16:
+ return CompilerType(clang_ast.weak_from_this(),
+ ast.Char16Ty.getAsOpaquePtr());
+ case PDB_BuiltinType::Char32:
+ return CompilerType(clang_ast.weak_from_this(),
+ ast.Char32Ty.getAsOpaquePtr());
+ case PDB_BuiltinType::Float:
+ // Note: types `long double` and `double` have same bit size in MSVC and
+ // there is no information in the PDB to distinguish them. So when falling
+ // back to default search, the compiler type of `long double` will be
+ // represented by the one generated for `double`.
+ break;
+ }
+ // If there is no match on PDB_BuiltinType, fall back to default search by
+ // encoding and width only
+ return clang_ast.GetBuiltinTypeForEncodingAndBitSize(encoding, width);
+}
+
+static ConstString GetPDBBuiltinTypeName(const PDBSymbolTypeBuiltin &pdb_type,
+ CompilerType &compiler_type) {
+ PDB_BuiltinType kind = pdb_type.getBuiltinType();
+ switch (kind) {
+ default:
+ break;
+ case PDB_BuiltinType::Currency:
+ return ConstString("CURRENCY");
+ case PDB_BuiltinType::Date:
+ return ConstString("DATE");
+ case PDB_BuiltinType::Variant:
+ return ConstString("VARIANT");
+ case PDB_BuiltinType::Complex:
+ return ConstString("complex");
+ case PDB_BuiltinType::Bitfield:
+ return ConstString("bitfield");
+ case PDB_BuiltinType::BSTR:
+ return ConstString("BSTR");
+ case PDB_BuiltinType::HResult:
+ return ConstString("HRESULT");
+ case PDB_BuiltinType::BCD:
+ return ConstString("BCD");
+ case PDB_BuiltinType::Char16:
+ return ConstString("char16_t");
+ case PDB_BuiltinType::Char32:
+ return ConstString("char32_t");
+ case PDB_BuiltinType::None:
+ return ConstString("...");
+ }
+ return compiler_type.GetTypeName();
+}
+
+static bool AddSourceInfoToDecl(const PDBSymbol &symbol, Declaration &decl) {
+ auto &raw_sym = symbol.getRawSymbol();
+ auto first_line_up = raw_sym.getSrcLineOnTypeDefn();
+
+ if (!first_line_up) {
+ auto lines_up = symbol.getSession().findLineNumbersByAddress(
+ raw_sym.getVirtualAddress(), raw_sym.getLength());
+ if (!lines_up)
+ return false;
+ first_line_up = lines_up->getNext();
+ if (!first_line_up)
+ return false;
+ }
+ uint32_t src_file_id = first_line_up->getSourceFileId();
+ auto src_file_up = symbol.getSession().getSourceFileById(src_file_id);
+ if (!src_file_up)
+ return false;
+
+ FileSpec spec(src_file_up->getFileName());
+ decl.SetFile(spec);
+ decl.SetColumn(first_line_up->getColumnNumber());
+ decl.SetLine(first_line_up->getLineNumber());
+ return true;
+}
+
+static AccessType TranslateMemberAccess(PDB_MemberAccess access) {
+ switch (access) {
+ case PDB_MemberAccess::Private:
+ return eAccessPrivate;
+ case PDB_MemberAccess::Protected:
+ return eAccessProtected;
+ case PDB_MemberAccess::Public:
+ return eAccessPublic;
+ }
+ return eAccessNone;
+}
+
+static AccessType GetDefaultAccessibilityForUdtKind(PDB_UdtType udt_kind) {
+ switch (udt_kind) {
+ case PDB_UdtType::Struct:
+ case PDB_UdtType::Union:
+ return eAccessPublic;
+ case PDB_UdtType::Class:
+ case PDB_UdtType::Interface:
+ return eAccessPrivate;
+ }
+ llvm_unreachable("unsupported PDB UDT type");
+}
+
+static AccessType GetAccessibilityForUdt(const PDBSymbolTypeUDT &udt) {
+ AccessType access = TranslateMemberAccess(udt.getAccess());
+ if (access != lldb::eAccessNone || !udt.isNested())
+ return access;
+
+ auto parent = udt.getClassParent();
+ if (!parent)
+ return lldb::eAccessNone;
+
+ auto parent_udt = llvm::dyn_cast<PDBSymbolTypeUDT>(parent.get());
+ if (!parent_udt)
+ return lldb::eAccessNone;
+
+ return GetDefaultAccessibilityForUdtKind(parent_udt->getUdtKind());
+}
+
+static clang::MSInheritanceAttr::Spelling
+GetMSInheritance(const PDBSymbolTypeUDT &udt) {
+ int base_count = 0;
+ bool has_virtual = false;
+
+ auto bases_enum = udt.findAllChildren<PDBSymbolTypeBaseClass>();
+ if (bases_enum) {
+ while (auto base = bases_enum->getNext()) {
+ base_count++;
+ has_virtual |= base->isVirtualBaseClass();
+ }
+ }
+
+ if (has_virtual)
+ return clang::MSInheritanceAttr::Keyword_virtual_inheritance;
+ if (base_count > 1)
+ return clang::MSInheritanceAttr::Keyword_multiple_inheritance;
+ return clang::MSInheritanceAttr::Keyword_single_inheritance;
+}
+
+static std::unique_ptr<llvm::pdb::PDBSymbol>
+GetClassOrFunctionParent(const llvm::pdb::PDBSymbol &symbol) {
+ const IPDBSession &session = symbol.getSession();
+ const IPDBRawSymbol &raw = symbol.getRawSymbol();
+ auto tag = symbol.getSymTag();
+
+ // For items that are nested inside of a class, return the class that it is
+ // nested inside of.
+ // Note that only certain items can be nested inside of classes.
+ switch (tag) {
+ case PDB_SymType::Function:
+ case PDB_SymType::Data:
+ case PDB_SymType::UDT:
+ case PDB_SymType::Enum:
+ case PDB_SymType::FunctionSig:
+ case PDB_SymType::Typedef:
+ case PDB_SymType::BaseClass:
+ case PDB_SymType::VTable: {
+ auto class_parent_id = raw.getClassParentId();
+ if (auto class_parent = session.getSymbolById(class_parent_id))
+ return class_parent;
+ break;
+ }
+ default:
+ break;
+ }
+
+ // Otherwise, if it is nested inside of a function, return the function.
+ // Note that only certain items can be nested inside of functions.
+ switch (tag) {
+ case PDB_SymType::Block:
+ case PDB_SymType::Data: {
+ auto lexical_parent_id = raw.getLexicalParentId();
+ auto lexical_parent = session.getSymbolById(lexical_parent_id);
+ if (!lexical_parent)
+ return nullptr;
+
+ auto lexical_parent_tag = lexical_parent->getSymTag();
+ if (lexical_parent_tag == PDB_SymType::Function)
+ return lexical_parent;
+ if (lexical_parent_tag == PDB_SymType::Exe)
+ return nullptr;
+
+ return GetClassOrFunctionParent(*lexical_parent);
+ }
+ default:
+ return nullptr;
+ }
+}
+
+static clang::NamedDecl *
+GetDeclFromContextByName(const clang::ASTContext &ast,
+ const clang::DeclContext &decl_context,
+ llvm::StringRef name) {
+ clang::IdentifierInfo &ident = ast.Idents.get(name);
+ clang::DeclarationName decl_name = ast.DeclarationNames.getIdentifier(&ident);
+ clang::DeclContext::lookup_result result = decl_context.lookup(decl_name);
+ if (result.empty())
+ return nullptr;
+
+ return *result.begin();
+}
+
+static bool IsAnonymousNamespaceName(llvm::StringRef name) {
+ return name == "`anonymous namespace'" || name == "`anonymous-namespace'";
+}
+
+static clang::CallingConv TranslateCallingConvention(PDB_CallingConv pdb_cc) {
+ switch (pdb_cc) {
+ case llvm::codeview::CallingConvention::NearC:
+ return clang::CC_C;
+ case llvm::codeview::CallingConvention::NearStdCall:
+ return clang::CC_X86StdCall;
+ case llvm::codeview::CallingConvention::NearFast:
+ return clang::CC_X86FastCall;
+ case llvm::codeview::CallingConvention::ThisCall:
+ return clang::CC_X86ThisCall;
+ case llvm::codeview::CallingConvention::NearVector:
+ return clang::CC_X86VectorCall;
+ case llvm::codeview::CallingConvention::NearPascal:
+ return clang::CC_X86Pascal;
+ default:
+ assert(false && "Unknown calling convention");
+ return clang::CC_C;
+ }
+}
+
+PDBASTParser::PDBASTParser(lldb_private::TypeSystemClang &ast) : m_ast(ast) {}
+
+PDBASTParser::~PDBASTParser() = default;
+
+// DebugInfoASTParser interface
+
+lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) {
+ Declaration decl;
+ switch (type.getSymTag()) {
+ case PDB_SymType::BaseClass: {
+ auto symbol_file = m_ast.GetSymbolFile();
+ if (!symbol_file)
+ return nullptr;
+
+ auto ty = symbol_file->ResolveTypeUID(type.getRawSymbol().getTypeId());
+ return ty ? ty->shared_from_this() : nullptr;
+ } break;
+ case PDB_SymType::UDT: {
+ auto udt = llvm::dyn_cast<PDBSymbolTypeUDT>(&type);
+ assert(udt);
+
+ // Note that, unnamed UDT being typedef-ed is generated as a UDT symbol
+ // other than a Typedef symbol in PDB. For example,
+ // typedef union { short Row; short Col; } Union;
+ // is generated as a named UDT in PDB:
+ // union Union { short Row; short Col; }
+ // Such symbols will be handled here.
+
+ // Some UDT with trival ctor has zero length. Just ignore.
+ if (udt->getLength() == 0)
+ return nullptr;
+
+ // Ignore unnamed-tag UDTs.
+ std::string name =
+ std::string(MSVCUndecoratedNameParser::DropScope(udt->getName()));
+ if (name.empty())
+ return nullptr;
+
+ auto decl_context = GetDeclContextContainingSymbol(type);
+
+ // Check if such an UDT already exists in the current context.
+ // This may occur with const or volatile types. There are separate type
+ // symbols in PDB for types with const or volatile modifiers, but we need
+ // to create only one declaration for them all.
+ Type::ResolveState type_resolve_state;
+ CompilerType clang_type =
+ m_ast.GetTypeForIdentifier<clang::CXXRecordDecl>(name, decl_context);
+ if (!clang_type.IsValid()) {
+ auto access = GetAccessibilityForUdt(*udt);
+
+ auto tag_type_kind = TranslateUdtKind(udt->getUdtKind());
+
+ ClangASTMetadata metadata;
+ metadata.SetUserID(type.getSymIndexId());
+ metadata.SetIsDynamicCXXType(false);
+
+ clang_type = m_ast.CreateRecordType(
+ decl_context, OptionalClangModuleID(), access, name, tag_type_kind,
+ lldb::eLanguageTypeC_plus_plus, &metadata);
+ assert(clang_type.IsValid());
+
+ auto record_decl =
+ m_ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType());
+ assert(record_decl);
+ m_uid_to_decl[type.getSymIndexId()] = record_decl;
+
+ auto inheritance_attr = clang::MSInheritanceAttr::CreateImplicit(
+ m_ast.getASTContext(), GetMSInheritance(*udt));
+ record_decl->addAttr(inheritance_attr);
+
+ TypeSystemClang::StartTagDeclarationDefinition(clang_type);
+
+ auto children = udt->findAllChildren();
+ if (!children || children->getChildCount() == 0) {
+ // PDB does not have symbol of forwarder. We assume we get an udt w/o
+ // any fields. Just complete it at this point.
+ TypeSystemClang::CompleteTagDeclarationDefinition(clang_type);
+
+ TypeSystemClang::SetHasExternalStorage(clang_type.GetOpaqueQualType(),
+ false);
+
+ type_resolve_state = Type::ResolveState::Full;
+ } else {
+ // Add the type to the forward declarations. It will help us to avoid
+ // an endless recursion in CompleteTypeFromUdt function.
+ m_forward_decl_to_uid[record_decl] = type.getSymIndexId();
+
+ TypeSystemClang::SetHasExternalStorage(clang_type.GetOpaqueQualType(),
+ true);
+
+ type_resolve_state = Type::ResolveState::Forward;
+ }
+ } else
+ type_resolve_state = Type::ResolveState::Forward;
+
+ if (udt->isConstType())
+ clang_type = clang_type.AddConstModifier();
+
+ if (udt->isVolatileType())
+ clang_type = clang_type.AddVolatileModifier();
+
+ AddSourceInfoToDecl(type, decl);
+ return m_ast.GetSymbolFile()->MakeType(
+ type.getSymIndexId(), ConstString(name), udt->getLength(), nullptr,
+ LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, clang_type,
+ type_resolve_state);
+ } break;
+ case PDB_SymType::Enum: {
+ auto enum_type = llvm::dyn_cast<PDBSymbolTypeEnum>(&type);
+ assert(enum_type);
+
+ std::string name =
+ std::string(MSVCUndecoratedNameParser::DropScope(enum_type->getName()));
+ auto decl_context = GetDeclContextContainingSymbol(type);
+ uint64_t bytes = enum_type->getLength();
+
+ // Check if such an enum already exists in the current context
+ CompilerType ast_enum =
+ m_ast.GetTypeForIdentifier<clang::EnumDecl>(name, decl_context);
+ if (!ast_enum.IsValid()) {
+ auto underlying_type_up = enum_type->getUnderlyingType();
+ if (!underlying_type_up)
+ return nullptr;
+
+ lldb::Encoding encoding =
+ TranslateBuiltinEncoding(underlying_type_up->getBuiltinType());
+ // FIXME: Type of underlying builtin is always `Int`. We correct it with
+ // the very first enumerator's encoding if any.
+ auto first_child = enum_type->findOneChild<PDBSymbolData>();
+ if (first_child)
+ encoding = TranslateEnumEncoding(first_child->getValue().Type);
+
+ CompilerType builtin_type;
+ if (bytes > 0)
+ builtin_type = GetBuiltinTypeForPDBEncodingAndBitSize(
+ m_ast, *underlying_type_up, encoding, bytes * 8);
+ else
+ builtin_type = m_ast.GetBasicType(eBasicTypeInt);
+
+ // FIXME: PDB does not have information about scoped enumeration (Enum
+ // Class). Set it false for now.
+ bool isScoped = false;
+
+ ast_enum = m_ast.CreateEnumerationType(name, decl_context,
+ OptionalClangModuleID(), decl,
+ builtin_type, isScoped);
+
+ auto enum_decl = TypeSystemClang::GetAsEnumDecl(ast_enum);
+ assert(enum_decl);
+ m_uid_to_decl[type.getSymIndexId()] = enum_decl;
+
+ auto enum_values = enum_type->findAllChildren<PDBSymbolData>();
+ if (enum_values) {
+ while (auto enum_value = enum_values->getNext()) {
+ if (enum_value->getDataKind() != PDB_DataKind::Constant)
+ continue;
+ AddEnumValue(ast_enum, *enum_value);
+ }
+ }
+
+ if (TypeSystemClang::StartTagDeclarationDefinition(ast_enum))
+ TypeSystemClang::CompleteTagDeclarationDefinition(ast_enum);
+ }
+
+ if (enum_type->isConstType())
+ ast_enum = ast_enum.AddConstModifier();
+
+ if (enum_type->isVolatileType())
+ ast_enum = ast_enum.AddVolatileModifier();
+
+ AddSourceInfoToDecl(type, decl);
+ return m_ast.GetSymbolFile()->MakeType(
+ type.getSymIndexId(), ConstString(name), bytes, nullptr,
+ LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, ast_enum,
+ lldb_private::Type::ResolveState::Full);
+ } break;
+ case PDB_SymType::Typedef: {
+ auto type_def = llvm::dyn_cast<PDBSymbolTypeTypedef>(&type);
+ assert(type_def);
+
+ SymbolFile *symbol_file = m_ast.GetSymbolFile();
+ if (!symbol_file)
+ return nullptr;
+
+ lldb_private::Type *target_type =
+ symbol_file->ResolveTypeUID(type_def->getTypeId());
+ if (!target_type)
+ return nullptr;
+
+ std::string name =
+ std::string(MSVCUndecoratedNameParser::DropScope(type_def->getName()));
+ auto decl_ctx = GetDeclContextContainingSymbol(type);
+
+ // Check if such a typedef already exists in the current context
+ CompilerType ast_typedef =
+ m_ast.GetTypeForIdentifier<clang::TypedefNameDecl>(name, decl_ctx);
+ if (!ast_typedef.IsValid()) {
+ CompilerType target_ast_type = target_type->GetFullCompilerType();
+
+ ast_typedef = target_ast_type.CreateTypedef(
+ name.c_str(), m_ast.CreateDeclContext(decl_ctx), 0);
+ if (!ast_typedef)
+ return nullptr;
+
+ auto typedef_decl = TypeSystemClang::GetAsTypedefDecl(ast_typedef);
+ assert(typedef_decl);
+ m_uid_to_decl[type.getSymIndexId()] = typedef_decl;
+ }
+
+ if (type_def->isConstType())
+ ast_typedef = ast_typedef.AddConstModifier();
+
+ if (type_def->isVolatileType())
+ ast_typedef = ast_typedef.AddVolatileModifier();
+
+ AddSourceInfoToDecl(type, decl);
+ std::optional<uint64_t> size;
+ if (type_def->getLength())
+ size = type_def->getLength();
+ return m_ast.GetSymbolFile()->MakeType(
+ type_def->getSymIndexId(), ConstString(name), size, nullptr,
+ target_type->GetID(), lldb_private::Type::eEncodingIsTypedefUID, decl,
+ ast_typedef, lldb_private::Type::ResolveState::Full);
+ } break;
+ case PDB_SymType::Function:
+ case PDB_SymType::FunctionSig: {
+ std::string name;
+ PDBSymbolTypeFunctionSig *func_sig = nullptr;
+ if (auto pdb_func = llvm::dyn_cast<PDBSymbolFunc>(&type)) {
+ if (pdb_func->isCompilerGenerated())
+ return nullptr;
+
+ auto sig = pdb_func->getSignature();
+ if (!sig)
+ return nullptr;
+ func_sig = sig.release();
+ // Function type is named.
+ name = std::string(
+ MSVCUndecoratedNameParser::DropScope(pdb_func->getName()));
+ } else if (auto pdb_func_sig =
+ llvm::dyn_cast<PDBSymbolTypeFunctionSig>(&type)) {
+ func_sig = const_cast<PDBSymbolTypeFunctionSig *>(pdb_func_sig);
+ } else
+ llvm_unreachable("Unexpected PDB symbol!");
+
+ auto arg_enum = func_sig->getArguments();
+ uint32_t num_args = arg_enum->getChildCount();
+ std::vector<CompilerType> arg_list;
+
+ bool is_variadic = func_sig->isCVarArgs();
+ // Drop last variadic argument.
+ if (is_variadic)
+ --num_args;
+ for (uint32_t arg_idx = 0; arg_idx < num_args; arg_idx++) {
+ auto arg = arg_enum->getChildAtIndex(arg_idx);
+ if (!arg)
+ break;
+
+ SymbolFile *symbol_file = m_ast.GetSymbolFile();
+ if (!symbol_file)
+ return nullptr;
+
+ lldb_private::Type *arg_type =
+ symbol_file->ResolveTypeUID(arg->getSymIndexId());
+ // If there's some error looking up one of the dependent types of this
+ // function signature, bail.
+ if (!arg_type)
+ return nullptr;
+ CompilerType arg_ast_type = arg_type->GetFullCompilerType();
+ arg_list.push_back(arg_ast_type);
+ }
+ lldbassert(arg_list.size() <= num_args);
+
+ auto pdb_return_type = func_sig->getReturnType();
+ SymbolFile *symbol_file = m_ast.GetSymbolFile();
+ if (!symbol_file)
+ return nullptr;
+
+ lldb_private::Type *return_type =
+ symbol_file->ResolveTypeUID(pdb_return_type->getSymIndexId());
+ // If there's some error looking up one of the dependent types of this
+ // function signature, bail.
+ if (!return_type)
+ return nullptr;
+ CompilerType return_ast_type = return_type->GetFullCompilerType();
+ uint32_t type_quals = 0;
+ if (func_sig->isConstType())
+ type_quals |= clang::Qualifiers::Const;
+ if (func_sig->isVolatileType())
+ type_quals |= clang::Qualifiers::Volatile;
+ auto cc = TranslateCallingConvention(func_sig->getCallingConvention());
+ CompilerType func_sig_ast_type =
+ m_ast.CreateFunctionType(return_ast_type, arg_list.data(),
+ arg_list.size(), is_variadic, type_quals, cc);
+
+ AddSourceInfoToDecl(type, decl);
+ return m_ast.GetSymbolFile()->MakeType(
+ type.getSymIndexId(), ConstString(name), std::nullopt, nullptr,
+ LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl,
+ func_sig_ast_type, lldb_private::Type::ResolveState::Full);
+ } break;
+ case PDB_SymType::ArrayType: {
+ auto array_type = llvm::dyn_cast<PDBSymbolTypeArray>(&type);
+ assert(array_type);
+ uint32_t num_elements = array_type->getCount();
+ uint32_t element_uid = array_type->getElementTypeId();
+ std::optional<uint64_t> bytes;
+ if (uint64_t size = array_type->getLength())
+ bytes = size;
+
+ SymbolFile *symbol_file = m_ast.GetSymbolFile();
+ if (!symbol_file)
+ return nullptr;
+
+ // If array rank > 0, PDB gives the element type at N=0. So element type
+ // will parsed in the order N=0, N=1,..., N=rank sequentially.
+ lldb_private::Type *element_type = symbol_file->ResolveTypeUID(element_uid);
+ if (!element_type)
+ return nullptr;
+
+ CompilerType element_ast_type = element_type->GetForwardCompilerType();
+ // If element type is UDT, it needs to be complete.
+ if (TypeSystemClang::IsCXXClassType(element_ast_type) &&
+ !element_ast_type.GetCompleteType()) {
+ if (TypeSystemClang::StartTagDeclarationDefinition(element_ast_type)) {
+ TypeSystemClang::CompleteTagDeclarationDefinition(element_ast_type);
+ } else {
+ // We are not able to start definition.
+ return nullptr;
+ }
+ }
+ CompilerType array_ast_type = m_ast.CreateArrayType(
+ element_ast_type, num_elements, /*is_gnu_vector*/ false);
+ TypeSP type_sp = m_ast.GetSymbolFile()->MakeType(
+ array_type->getSymIndexId(), ConstString(), bytes, nullptr,
+ LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl,
+ array_ast_type, lldb_private::Type::ResolveState::Full);
+ type_sp->SetEncodingType(element_type);
+ return type_sp;
+ } break;
+ case PDB_SymType::BuiltinType: {
+ auto *builtin_type = llvm::dyn_cast<PDBSymbolTypeBuiltin>(&type);
+ assert(builtin_type);
+ PDB_BuiltinType builtin_kind = builtin_type->getBuiltinType();
+ if (builtin_kind == PDB_BuiltinType::None)
+ return nullptr;
+
+ std::optional<uint64_t> bytes;
+ if (uint64_t size = builtin_type->getLength())
+ bytes = size;
+ Encoding encoding = TranslateBuiltinEncoding(builtin_kind);
+ CompilerType builtin_ast_type = GetBuiltinTypeForPDBEncodingAndBitSize(
+ m_ast, *builtin_type, encoding, bytes.value_or(0) * 8);
+
+ if (builtin_type->isConstType())
+ builtin_ast_type = builtin_ast_type.AddConstModifier();
+
+ if (builtin_type->isVolatileType())
+ builtin_ast_type = builtin_ast_type.AddVolatileModifier();
+
+ auto type_name = GetPDBBuiltinTypeName(*builtin_type, builtin_ast_type);
+
+ return m_ast.GetSymbolFile()->MakeType(
+ builtin_type->getSymIndexId(), type_name, bytes, nullptr,
+ LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl,
+ builtin_ast_type, lldb_private::Type::ResolveState::Full);
+ } break;
+ case PDB_SymType::PointerType: {
+ auto *pointer_type = llvm::dyn_cast<PDBSymbolTypePointer>(&type);
+ assert(pointer_type);
+
+ SymbolFile *symbol_file = m_ast.GetSymbolFile();
+ if (!symbol_file)
+ return nullptr;
+
+ Type *pointee_type = symbol_file->ResolveTypeUID(
+ pointer_type->getPointeeType()->getSymIndexId());
+ if (!pointee_type)
+ return nullptr;
+
+ if (pointer_type->isPointerToDataMember() ||
+ pointer_type->isPointerToMemberFunction()) {
+ auto class_parent_uid = pointer_type->getRawSymbol().getClassParentId();
+ auto class_parent_type = symbol_file->ResolveTypeUID(class_parent_uid);
+ assert(class_parent_type);
+
+ CompilerType pointer_ast_type;
+ pointer_ast_type = TypeSystemClang::CreateMemberPointerType(
+ class_parent_type->GetLayoutCompilerType(),
+ pointee_type->GetForwardCompilerType());
+ assert(pointer_ast_type);
+
+ return m_ast.GetSymbolFile()->MakeType(
+ pointer_type->getSymIndexId(), ConstString(),
+ pointer_type->getLength(), nullptr, LLDB_INVALID_UID,
+ lldb_private::Type::eEncodingIsUID, decl, pointer_ast_type,
+ lldb_private::Type::ResolveState::Forward);
+ }
+
+ CompilerType pointer_ast_type;
+ pointer_ast_type = pointee_type->GetFullCompilerType();
+ if (pointer_type->isReference())
+ pointer_ast_type = pointer_ast_type.GetLValueReferenceType();
+ else if (pointer_type->isRValueReference())
+ pointer_ast_type = pointer_ast_type.GetRValueReferenceType();
+ else
+ pointer_ast_type = pointer_ast_type.GetPointerType();
+
+ if (pointer_type->isConstType())
+ pointer_ast_type = pointer_ast_type.AddConstModifier();
+
+ if (pointer_type->isVolatileType())
+ pointer_ast_type = pointer_ast_type.AddVolatileModifier();
+
+ if (pointer_type->isRestrictedType())
+ pointer_ast_type = pointer_ast_type.AddRestrictModifier();
+
+ return m_ast.GetSymbolFile()->MakeType(
+ pointer_type->getSymIndexId(), ConstString(), pointer_type->getLength(),
+ nullptr, LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl,
+ pointer_ast_type, lldb_private::Type::ResolveState::Full);
+ } break;
+ default:
+ break;
+ }
+ return nullptr;
+}
+
+bool PDBASTParser::CompleteTypeFromPDB(
+ lldb_private::CompilerType &compiler_type) {
+ if (GetClangASTImporter().CanImport(compiler_type))
+ return GetClangASTImporter().CompleteType(compiler_type);
+
+ // Remove the type from the forward declarations to avoid
+ // an endless recursion for types like a linked list.
+ clang::CXXRecordDecl *record_decl =
+ m_ast.GetAsCXXRecordDecl(compiler_type.GetOpaqueQualType());
+ auto uid_it = m_forward_decl_to_uid.find(record_decl);
+ if (uid_it == m_forward_decl_to_uid.end())
+ return true;
+
+ auto symbol_file = static_cast<SymbolFilePDB *>(
+ m_ast.GetSymbolFile()->GetBackingSymbolFile());
+ if (!symbol_file)
+ return false;
+
+ std::unique_ptr<PDBSymbol> symbol =
+ symbol_file->GetPDBSession().getSymbolById(uid_it->getSecond());
+ if (!symbol)
+ return false;
+
+ m_forward_decl_to_uid.erase(uid_it);
+
+ TypeSystemClang::SetHasExternalStorage(compiler_type.GetOpaqueQualType(),
+ false);
+
+ switch (symbol->getSymTag()) {
+ case PDB_SymType::UDT: {
+ auto udt = llvm::dyn_cast<PDBSymbolTypeUDT>(symbol.get());
+ if (!udt)
+ return false;
+
+ return CompleteTypeFromUDT(*symbol_file, compiler_type, *udt);
+ }
+ default:
+ llvm_unreachable("not a forward clang type decl!");
+ }
+}
+
+clang::Decl *
+PDBASTParser::GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol) {
+ uint32_t sym_id = symbol.getSymIndexId();
+ auto it = m_uid_to_decl.find(sym_id);
+ if (it != m_uid_to_decl.end())
+ return it->second;
+
+ auto symbol_file = static_cast<SymbolFilePDB *>(
+ m_ast.GetSymbolFile()->GetBackingSymbolFile());
+ if (!symbol_file)
+ return nullptr;
+
+ // First of all, check if the symbol is a member of a class. Resolve the full
+ // class type and return the declaration from the cache if so.
+ auto tag = symbol.getSymTag();
+ if (tag == PDB_SymType::Data || tag == PDB_SymType::Function) {
+ const IPDBSession &session = symbol.getSession();
+ const IPDBRawSymbol &raw = symbol.getRawSymbol();
+
+ auto class_parent_id = raw.getClassParentId();
+ if (std::unique_ptr<PDBSymbol> class_parent =
+ session.getSymbolById(class_parent_id)) {
+ auto class_parent_type = symbol_file->ResolveTypeUID(class_parent_id);
+ if (!class_parent_type)
+ return nullptr;
+
+ CompilerType class_parent_ct = class_parent_type->GetFullCompilerType();
+
+ // Look a declaration up in the cache after completing the class
+ clang::Decl *decl = m_uid_to_decl.lookup(sym_id);
+ if (decl)
+ return decl;
+
+ // A declaration was not found in the cache. It means that the symbol
+ // has the class parent, but the class doesn't have the symbol in its
+ // children list.
+ if (auto func = llvm::dyn_cast_or_null<PDBSymbolFunc>(&symbol)) {
+ // Try to find a class child method with the same RVA and use its
+ // declaration if found.
+ if (uint32_t rva = func->getRelativeVirtualAddress()) {
+ if (std::unique_ptr<ConcreteSymbolEnumerator<PDBSymbolFunc>>
+ methods_enum =
+ class_parent->findAllChildren<PDBSymbolFunc>()) {
+ while (std::unique_ptr<PDBSymbolFunc> method =
+ methods_enum->getNext()) {
+ if (method->getRelativeVirtualAddress() == rva) {
+ decl = m_uid_to_decl.lookup(method->getSymIndexId());
+ if (decl)
+ break;
+ }
+ }
+ }
+ }
+
+ // If no class methods with the same RVA were found, then create a new
+ // method. It is possible for template methods.
+ if (!decl)
+ decl = AddRecordMethod(*symbol_file, class_parent_ct, *func);
+ }
+
+ if (decl)
+ m_uid_to_decl[sym_id] = decl;
+
+ return decl;
+ }
+ }
+
+ // If we are here, then the symbol is not belonging to a class and is not
+ // contained in the cache. So create a declaration for it.
+ switch (symbol.getSymTag()) {
+ case PDB_SymType::Data: {
+ auto data = llvm::dyn_cast<PDBSymbolData>(&symbol);
+ assert(data);
+
+ auto decl_context = GetDeclContextContainingSymbol(symbol);
+ assert(decl_context);
+
+ // May be the current context is a class really, but we haven't found
+ // any class parent. This happens e.g. in the case of class static
+ // variables - they has two symbols, one is a child of the class when
+ // another is a child of the exe. So always complete the parent and use
+ // an existing declaration if possible.
+ if (auto parent_decl = llvm::dyn_cast_or_null<clang::TagDecl>(decl_context))
+ m_ast.GetCompleteDecl(parent_decl);
+
+ std::string name =
+ std::string(MSVCUndecoratedNameParser::DropScope(data->getName()));
+
+ // Check if the current context already contains the symbol with the name.
+ clang::Decl *decl =
+ GetDeclFromContextByName(m_ast.getASTContext(), *decl_context, name);
+ if (!decl) {
+ auto type = symbol_file->ResolveTypeUID(data->getTypeId());
+ if (!type)
+ return nullptr;
+
+ decl = m_ast.CreateVariableDeclaration(
+ decl_context, OptionalClangModuleID(), name.c_str(),
+ ClangUtil::GetQualType(type->GetLayoutCompilerType()));
+ }
+
+ m_uid_to_decl[sym_id] = decl;
+
+ return decl;
+ }
+ case PDB_SymType::Function: {
+ auto func = llvm::dyn_cast<PDBSymbolFunc>(&symbol);
+ assert(func);
+
+ auto decl_context = GetDeclContextContainingSymbol(symbol);
+ assert(decl_context);
+
+ std::string name =
+ std::string(MSVCUndecoratedNameParser::DropScope(func->getName()));
+
+ Type *type = symbol_file->ResolveTypeUID(sym_id);
+ if (!type)
+ return nullptr;
+
+ auto storage = func->isStatic() ? clang::StorageClass::SC_Static
+ : clang::StorageClass::SC_None;
+
+ auto decl = m_ast.CreateFunctionDeclaration(
+ decl_context, OptionalClangModuleID(), name,
+ type->GetForwardCompilerType(), storage, func->hasInlineAttribute());
+
+ std::vector<clang::ParmVarDecl *> params;
+ if (std::unique_ptr<PDBSymbolTypeFunctionSig> sig = func->getSignature()) {
+ if (std::unique_ptr<ConcreteSymbolEnumerator<PDBSymbolTypeFunctionArg>>
+ arg_enum = sig->findAllChildren<PDBSymbolTypeFunctionArg>()) {
+ while (std::unique_ptr<PDBSymbolTypeFunctionArg> arg =
+ arg_enum->getNext()) {
+ Type *arg_type = symbol_file->ResolveTypeUID(arg->getTypeId());
+ if (!arg_type)
+ continue;
+
+ clang::ParmVarDecl *param = m_ast.CreateParameterDeclaration(
+ decl, OptionalClangModuleID(), nullptr,
+ arg_type->GetForwardCompilerType(), clang::SC_None, true);
+ if (param)
+ params.push_back(param);
+ }
+ }
+ }
+ if (params.size())
+ m_ast.SetFunctionParameters(decl, params);
+
+ m_uid_to_decl[sym_id] = decl;
+
+ return decl;
+ }
+ default: {
+ // It's not a variable and not a function, check if it's a type
+ Type *type = symbol_file->ResolveTypeUID(sym_id);
+ if (!type)
+ return nullptr;
+
+ return m_uid_to_decl.lookup(sym_id);
+ }
+ }
+}
+
+clang::DeclContext *
+PDBASTParser::GetDeclContextForSymbol(const llvm::pdb::PDBSymbol &symbol) {
+ if (symbol.getSymTag() == PDB_SymType::Function) {
+ clang::DeclContext *result =
+ llvm::dyn_cast_or_null<clang::FunctionDecl>(GetDeclForSymbol(symbol));
+
+ if (result)
+ m_decl_context_to_uid[result] = symbol.getSymIndexId();
+
+ return result;
+ }
+
+ auto symbol_file = static_cast<SymbolFilePDB *>(
+ m_ast.GetSymbolFile()->GetBackingSymbolFile());
+ if (!symbol_file)
+ return nullptr;
+
+ auto type = symbol_file->ResolveTypeUID(symbol.getSymIndexId());
+ if (!type)
+ return nullptr;
+
+ clang::DeclContext *result =
+ m_ast.GetDeclContextForType(type->GetForwardCompilerType());
+
+ if (result)
+ m_decl_context_to_uid[result] = symbol.getSymIndexId();
+
+ return result;
+}
+
+clang::DeclContext *PDBASTParser::GetDeclContextContainingSymbol(
+ const llvm::pdb::PDBSymbol &symbol) {
+ auto parent = GetClassOrFunctionParent(symbol);
+ while (parent) {
+ if (auto parent_context = GetDeclContextForSymbol(*parent))
+ return parent_context;
+
+ parent = GetClassOrFunctionParent(*parent);
+ }
+
+ // We can't find any class or function parent of the symbol. So analyze
+ // the full symbol name. The symbol may be belonging to a namespace
+ // or function (or even to a class if it's e.g. a static variable symbol).
+
+ // TODO: Make clang to emit full names for variables in namespaces
+ // (as MSVC does)
+
+ std::string name(symbol.getRawSymbol().getName());
+ MSVCUndecoratedNameParser parser(name);
+ llvm::ArrayRef<MSVCUndecoratedNameSpecifier> specs = parser.GetSpecifiers();
+ if (specs.empty())
+ return m_ast.GetTranslationUnitDecl();
+
+ auto symbol_file = static_cast<SymbolFilePDB *>(
+ m_ast.GetSymbolFile()->GetBackingSymbolFile());
+ if (!symbol_file)
+ return m_ast.GetTranslationUnitDecl();
+
+ auto global = symbol_file->GetPDBSession().getGlobalScope();
+ if (!global)
+ return m_ast.GetTranslationUnitDecl();
+
+ bool has_type_or_function_parent = false;
+ clang::DeclContext *curr_context = m_ast.GetTranslationUnitDecl();
+ for (std::size_t i = 0; i < specs.size() - 1; i++) {
+ // Check if there is a function or a type with the current context's name.
+ if (std::unique_ptr<IPDBEnumSymbols> children_enum = global->findChildren(
+ PDB_SymType::None, specs[i].GetFullName(), NS_CaseSensitive)) {
+ while (IPDBEnumChildren<PDBSymbol>::ChildTypePtr child =
+ children_enum->getNext()) {
+ if (clang::DeclContext *child_context =
+ GetDeclContextForSymbol(*child)) {
+ // Note that `GetDeclContextForSymbol' retrieves
+ // a declaration context for functions and types only,
+ // so if we are here then `child_context' is guaranteed
+ // a function or a type declaration context.
+ has_type_or_function_parent = true;
+ curr_context = child_context;
+ }
+ }
+ }
+
+ // If there were no functions or types above then retrieve a namespace with
+ // the current context's name. There can be no namespaces inside a function
+ // or a type. We check it to avoid fake namespaces such as `__l2':
+ // `N0::N1::CClass::PrivateFunc::__l2::InnerFuncStruct'
+ if (!has_type_or_function_parent) {
+ std::string namespace_name = std::string(specs[i].GetBaseName());
+ const char *namespace_name_c_str =
+ IsAnonymousNamespaceName(namespace_name) ? nullptr
+ : namespace_name.data();
+ clang::NamespaceDecl *namespace_decl =
+ m_ast.GetUniqueNamespaceDeclaration(
+ namespace_name_c_str, curr_context, OptionalClangModuleID());
+
+ m_parent_to_namespaces[curr_context].insert(namespace_decl);
+ m_namespaces.insert(namespace_decl);
+
+ curr_context = namespace_decl;
+ }
+ }
+
+ return curr_context;
+}
+
+void PDBASTParser::ParseDeclsForDeclContext(
+ const clang::DeclContext *decl_context) {
+ auto symbol_file = static_cast<SymbolFilePDB *>(
+ m_ast.GetSymbolFile()->GetBackingSymbolFile());
+ if (!symbol_file)
+ return;
+
+ IPDBSession &session = symbol_file->GetPDBSession();
+ auto symbol_up =
+ session.getSymbolById(m_decl_context_to_uid.lookup(decl_context));
+ auto global_up = session.getGlobalScope();
+
+ PDBSymbol *symbol;
+ if (symbol_up)
+ symbol = symbol_up.get();
+ else if (global_up)
+ symbol = global_up.get();
+ else
+ return;
+
+ if (auto children = symbol->findAllChildren())
+ while (auto child = children->getNext())
+ GetDeclForSymbol(*child);
+}
+
+clang::NamespaceDecl *
+PDBASTParser::FindNamespaceDecl(const clang::DeclContext *parent,
+ llvm::StringRef name) {
+ NamespacesSet *set;
+ if (parent) {
+ auto pit = m_parent_to_namespaces.find(parent);
+ if (pit == m_parent_to_namespaces.end())
+ return nullptr;
+
+ set = &pit->second;
+ } else {
+ set = &m_namespaces;
+ }
+ assert(set);
+
+ for (clang::NamespaceDecl *namespace_decl : *set)
+ if (namespace_decl->getName() == name)
+ return namespace_decl;
+
+ for (clang::NamespaceDecl *namespace_decl : *set)
+ if (namespace_decl->isAnonymousNamespace())
+ return FindNamespaceDecl(namespace_decl, name);
+
+ return nullptr;
+}
+
+bool PDBASTParser::AddEnumValue(CompilerType enum_type,
+ const PDBSymbolData &enum_value) {
+ Declaration decl;
+ Variant v = enum_value.getValue();
+ std::string name =
+ std::string(MSVCUndecoratedNameParser::DropScope(enum_value.getName()));
+ int64_t raw_value;
+ switch (v.Type) {
+ case PDB_VariantType::Int8:
+ raw_value = v.Value.Int8;
+ break;
+ case PDB_VariantType::Int16:
+ raw_value = v.Value.Int16;
+ break;
+ case PDB_VariantType::Int32:
+ raw_value = v.Value.Int32;
+ break;
+ case PDB_VariantType::Int64:
+ raw_value = v.Value.Int64;
+ break;
+ case PDB_VariantType::UInt8:
+ raw_value = v.Value.UInt8;
+ break;
+ case PDB_VariantType::UInt16:
+ raw_value = v.Value.UInt16;
+ break;
+ case PDB_VariantType::UInt32:
+ raw_value = v.Value.UInt32;
+ break;
+ case PDB_VariantType::UInt64:
+ raw_value = v.Value.UInt64;
+ break;
+ default:
+ return false;
+ }
+ CompilerType underlying_type = m_ast.GetEnumerationIntegerType(enum_type);
+ uint32_t byte_size = m_ast.getASTContext().getTypeSize(
+ ClangUtil::GetQualType(underlying_type));
+ auto enum_constant_decl = m_ast.AddEnumerationValueToEnumerationType(
+ enum_type, decl, name.c_str(), raw_value, byte_size * 8);
+ if (!enum_constant_decl)
+ return false;
+
+ m_uid_to_decl[enum_value.getSymIndexId()] = enum_constant_decl;
+
+ return true;
+}
+
+bool PDBASTParser::CompleteTypeFromUDT(
+ lldb_private::SymbolFile &symbol_file,
+ lldb_private::CompilerType &compiler_type,
+ llvm::pdb::PDBSymbolTypeUDT &udt) {
+ ClangASTImporter::LayoutInfo layout_info;
+ layout_info.bit_size = udt.getLength() * 8;
+
+ auto nested_enums = udt.findAllChildren<PDBSymbolTypeUDT>();
+ if (nested_enums)
+ while (auto nested = nested_enums->getNext())
+ symbol_file.ResolveTypeUID(nested->getSymIndexId());
+
+ auto bases_enum = udt.findAllChildren<PDBSymbolTypeBaseClass>();
+ if (bases_enum)
+ AddRecordBases(symbol_file, compiler_type,
+ TranslateUdtKind(udt.getUdtKind()), *bases_enum,
+ layout_info);
+
+ auto members_enum = udt.findAllChildren<PDBSymbolData>();
+ if (members_enum)
+ AddRecordMembers(symbol_file, compiler_type, *members_enum, layout_info);
+
+ auto methods_enum = udt.findAllChildren<PDBSymbolFunc>();
+ if (methods_enum)
+ AddRecordMethods(symbol_file, compiler_type, *methods_enum);
+
+ m_ast.AddMethodOverridesForCXXRecordType(compiler_type.GetOpaqueQualType());
+ TypeSystemClang::BuildIndirectFields(compiler_type);
+ TypeSystemClang::CompleteTagDeclarationDefinition(compiler_type);
+
+ clang::CXXRecordDecl *record_decl =
+ m_ast.GetAsCXXRecordDecl(compiler_type.GetOpaqueQualType());
+ if (!record_decl)
+ return static_cast<bool>(compiler_type);
+
+ GetClangASTImporter().SetRecordLayout(record_decl, layout_info);
+
+ return static_cast<bool>(compiler_type);
+}
+
+void PDBASTParser::AddRecordMembers(
+ lldb_private::SymbolFile &symbol_file,
+ lldb_private::CompilerType &record_type,
+ PDBDataSymbolEnumerator &members_enum,
+ lldb_private::ClangASTImporter::LayoutInfo &layout_info) {
+ while (auto member = members_enum.getNext()) {
+ if (member->isCompilerGenerated())
+ continue;
+
+ auto member_name = member->getName();
+
+ auto member_type = symbol_file.ResolveTypeUID(member->getTypeId());
+ if (!member_type)
+ continue;
+
+ auto member_comp_type = member_type->GetLayoutCompilerType();
+ if (!member_comp_type.GetCompleteType()) {
+ symbol_file.GetObjectFile()->GetModule()->ReportError(
+ ":: Class '{0}' has a member '{1}' of type '{2}' "
+ "which does not have a complete definition.",
+ record_type.GetTypeName().GetCString(), member_name.c_str(),
+ member_comp_type.GetTypeName().GetCString());
+ if (TypeSystemClang::StartTagDeclarationDefinition(member_comp_type))
+ TypeSystemClang::CompleteTagDeclarationDefinition(member_comp_type);
+ }
+
+ auto access = TranslateMemberAccess(member->getAccess());
+
+ switch (member->getDataKind()) {
+ case PDB_DataKind::Member: {
+ auto location_type = member->getLocationType();
+
+ auto bit_size = member->getLength();
+ if (location_type == PDB_LocType::ThisRel)
+ bit_size *= 8;
+
+ auto decl = TypeSystemClang::AddFieldToRecordType(
+ record_type, member_name.c_str(), member_comp_type, access, bit_size);
+ if (!decl)
+ continue;
+
+ m_uid_to_decl[member->getSymIndexId()] = decl;
+
+ auto offset = member->getOffset() * 8;
+ if (location_type == PDB_LocType::BitField)
+ offset += member->getBitPosition();
+
+ layout_info.field_offsets.insert(std::make_pair(decl, offset));
+
+ break;
+ }
+ case PDB_DataKind::StaticMember: {
+ auto decl = TypeSystemClang::AddVariableToRecordType(
+ record_type, member_name.c_str(), member_comp_type, access);
+ if (!decl)
+ continue;
+
+ // Static constant members may be a const[expr] declaration.
+ // Query the symbol's value as the variable initializer if valid.
+ if (member_comp_type.IsConst()) {
+ auto value = member->getValue();
+ if (value.Type == llvm::pdb::Empty) {
+ LLDB_LOG(GetLog(LLDBLog::AST),
+ "Class '{0}' has member '{1}' of type '{2}' with an unknown "
+ "constant size.",
+ record_type.GetTypeName(), member_name,
+ member_comp_type.GetTypeName());
+ continue;
+ }
+
+ clang::QualType qual_type = decl->getType();
+ unsigned type_width = m_ast.getASTContext().getIntWidth(qual_type);
+ unsigned constant_width = value.getBitWidth();
+
+ if (qual_type->isIntegralOrEnumerationType()) {
+ if (type_width >= constant_width) {
+ TypeSystemClang::SetIntegerInitializerForVariable(
+ decl, value.toAPSInt().extOrTrunc(type_width));
+ } else {
+ LLDB_LOG(GetLog(LLDBLog::AST),
+ "Class '{0}' has a member '{1}' of type '{2}' ({3} bits) "
+ "which resolves to a wider constant value ({4} bits). "
+ "Ignoring constant.",
+ record_type.GetTypeName(), member_name,
+ member_comp_type.GetTypeName(), type_width,
+ constant_width);
+ }
+ } else {
+ switch (member_comp_type.GetBasicTypeEnumeration()) {
+ case lldb::eBasicTypeFloat:
+ case lldb::eBasicTypeDouble:
+ case lldb::eBasicTypeLongDouble:
+ if (type_width == constant_width) {
+ TypeSystemClang::SetFloatingInitializerForVariable(
+ decl, value.toAPFloat());
+ decl->setConstexpr(true);
+ } else {
+ LLDB_LOG(GetLog(LLDBLog::AST),
+ "Class '{0}' has a member '{1}' of type '{2}' ({3} "
+ "bits) which resolves to a constant value of mismatched "
+ "width ({4} bits). Ignoring constant.",
+ record_type.GetTypeName(), member_name,
+ member_comp_type.GetTypeName(), type_width,
+ constant_width);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ m_uid_to_decl[member->getSymIndexId()] = decl;
+
+ break;
+ }
+ default:
+ llvm_unreachable("unsupported PDB data kind");
+ }
+ }
+}
+
+void PDBASTParser::AddRecordBases(
+ lldb_private::SymbolFile &symbol_file,
+ lldb_private::CompilerType &record_type, int record_kind,
+ PDBBaseClassSymbolEnumerator &bases_enum,
+ lldb_private::ClangASTImporter::LayoutInfo &layout_info) const {
+ std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> base_classes;
+
+ while (auto base = bases_enum.getNext()) {
+ auto base_type = symbol_file.ResolveTypeUID(base->getTypeId());
+ if (!base_type)
+ continue;
+
+ auto base_comp_type = base_type->GetFullCompilerType();
+ if (!base_comp_type.GetCompleteType()) {
+ symbol_file.GetObjectFile()->GetModule()->ReportError(
+ ":: Class '{0}' has a base class '{1}' "
+ "which does not have a complete definition.",
+ record_type.GetTypeName().GetCString(),
+ base_comp_type.GetTypeName().GetCString());
+ if (TypeSystemClang::StartTagDeclarationDefinition(base_comp_type))
+ TypeSystemClang::CompleteTagDeclarationDefinition(base_comp_type);
+ }
+
+ auto access = TranslateMemberAccess(base->getAccess());
+
+ auto is_virtual = base->isVirtualBaseClass();
+
+ std::unique_ptr<clang::CXXBaseSpecifier> base_spec =
+ m_ast.CreateBaseClassSpecifier(
+ base_comp_type.GetOpaqueQualType(), access, is_virtual,
+ record_kind == llvm::to_underlying(clang::TagTypeKind::Class));
+ lldbassert(base_spec);
+
+ base_classes.push_back(std::move(base_spec));
+
+ if (is_virtual)
+ continue;
+
+ auto decl = m_ast.GetAsCXXRecordDecl(base_comp_type.GetOpaqueQualType());
+ if (!decl)
+ continue;
+
+ auto offset = clang::CharUnits::fromQuantity(base->getOffset());
+ layout_info.base_offsets.insert(std::make_pair(decl, offset));
+ }
+
+ m_ast.TransferBaseClasses(record_type.GetOpaqueQualType(),
+ std::move(base_classes));
+}
+
+void PDBASTParser::AddRecordMethods(lldb_private::SymbolFile &symbol_file,
+ lldb_private::CompilerType &record_type,
+ PDBFuncSymbolEnumerator &methods_enum) {
+ while (std::unique_ptr<PDBSymbolFunc> method = methods_enum.getNext())
+ if (clang::CXXMethodDecl *decl =
+ AddRecordMethod(symbol_file, record_type, *method))
+ m_uid_to_decl[method->getSymIndexId()] = decl;
+}
+
+clang::CXXMethodDecl *
+PDBASTParser::AddRecordMethod(lldb_private::SymbolFile &symbol_file,
+ lldb_private::CompilerType &record_type,
+ const llvm::pdb::PDBSymbolFunc &method) const {
+ std::string name =
+ std::string(MSVCUndecoratedNameParser::DropScope(method.getName()));
+
+ Type *method_type = symbol_file.ResolveTypeUID(method.getSymIndexId());
+ // MSVC specific __vecDelDtor.
+ if (!method_type)
+ return nullptr;
+
+ CompilerType method_comp_type = method_type->GetFullCompilerType();
+ if (!method_comp_type.GetCompleteType()) {
+ symbol_file.GetObjectFile()->GetModule()->ReportError(
+ ":: Class '{0}' has a method '{1}' whose type cannot be completed.",
+ record_type.GetTypeName().GetCString(),
+ method_comp_type.GetTypeName().GetCString());
+ if (TypeSystemClang::StartTagDeclarationDefinition(method_comp_type))
+ TypeSystemClang::CompleteTagDeclarationDefinition(method_comp_type);
+ }
+
+ AccessType access = TranslateMemberAccess(method.getAccess());
+ if (access == eAccessNone)
+ access = eAccessPublic;
+
+ // TODO: get mangled name for the method.
+ return m_ast.AddMethodToCXXRecordType(
+ record_type.GetOpaqueQualType(), name.c_str(),
+ /*mangled_name*/ nullptr, method_comp_type, access, method.isVirtual(),
+ method.isStatic(), method.hasInlineAttribute(),
+ /*is_explicit*/ false, // FIXME: Need this field in CodeView.
+ /*is_attr_used*/ false,
+ /*is_artificial*/ method.isCompilerGenerated());
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.h
new file mode 100644
index 000000000000..06f317f4c4d9
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.h
@@ -0,0 +1,116 @@
+//===-- PDBASTParser.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_PDB_PDBASTPARSER_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_PDB_PDBASTPARSER_H
+
+#include "lldb/lldb-forward.h"
+
+#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
+
+class SymbolFilePDB;
+
+namespace clang {
+class CharUnits;
+class CXXRecordDecl;
+class FieldDecl;
+class RecordDecl;
+} // namespace clang
+
+namespace lldb_private {
+class TypeSystemClang;
+class CompilerType;
+} // namespace lldb_private
+
+namespace llvm {
+namespace pdb {
+template <typename ChildType> class ConcreteSymbolEnumerator;
+
+class PDBSymbol;
+class PDBSymbolData;
+class PDBSymbolFunc;
+class PDBSymbolTypeBaseClass;
+class PDBSymbolTypeBuiltin;
+class PDBSymbolTypeUDT;
+} // namespace pdb
+} // namespace llvm
+
+class PDBASTParser {
+public:
+ PDBASTParser(lldb_private::TypeSystemClang &ast);
+ ~PDBASTParser();
+
+ lldb::TypeSP CreateLLDBTypeFromPDBType(const llvm::pdb::PDBSymbol &type);
+ bool CompleteTypeFromPDB(lldb_private::CompilerType &compiler_type);
+
+ clang::Decl *GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol);
+
+ clang::DeclContext *
+ GetDeclContextForSymbol(const llvm::pdb::PDBSymbol &symbol);
+ clang::DeclContext *
+ GetDeclContextContainingSymbol(const llvm::pdb::PDBSymbol &symbol);
+
+ void ParseDeclsForDeclContext(const clang::DeclContext *decl_context);
+
+ clang::NamespaceDecl *FindNamespaceDecl(const clang::DeclContext *parent,
+ llvm::StringRef name);
+
+ lldb_private::ClangASTImporter &GetClangASTImporter() {
+ return m_ast_importer;
+ }
+
+private:
+ typedef llvm::DenseMap<clang::CXXRecordDecl *, lldb::user_id_t>
+ CXXRecordDeclToUidMap;
+ typedef llvm::DenseMap<lldb::user_id_t, clang::Decl *> UidToDeclMap;
+ typedef std::set<clang::NamespaceDecl *> NamespacesSet;
+ typedef llvm::DenseMap<clang::DeclContext *, NamespacesSet>
+ ParentToNamespacesMap;
+ typedef llvm::DenseMap<clang::DeclContext *, lldb::user_id_t>
+ DeclContextToUidMap;
+ typedef llvm::pdb::ConcreteSymbolEnumerator<llvm::pdb::PDBSymbolData>
+ PDBDataSymbolEnumerator;
+ typedef llvm::pdb::ConcreteSymbolEnumerator<llvm::pdb::PDBSymbolTypeBaseClass>
+ PDBBaseClassSymbolEnumerator;
+ typedef llvm::pdb::ConcreteSymbolEnumerator<llvm::pdb::PDBSymbolFunc>
+ PDBFuncSymbolEnumerator;
+
+ bool AddEnumValue(lldb_private::CompilerType enum_type,
+ const llvm::pdb::PDBSymbolData &data);
+ bool CompleteTypeFromUDT(lldb_private::SymbolFile &symbol_file,
+ lldb_private::CompilerType &compiler_type,
+ llvm::pdb::PDBSymbolTypeUDT &udt);
+ void
+ AddRecordMembers(lldb_private::SymbolFile &symbol_file,
+ lldb_private::CompilerType &record_type,
+ PDBDataSymbolEnumerator &members_enum,
+ lldb_private::ClangASTImporter::LayoutInfo &layout_info);
+ void
+ AddRecordBases(lldb_private::SymbolFile &symbol_file,
+ lldb_private::CompilerType &record_type, int record_kind,
+ PDBBaseClassSymbolEnumerator &bases_enum,
+ lldb_private::ClangASTImporter::LayoutInfo &layout_info) const;
+ void AddRecordMethods(lldb_private::SymbolFile &symbol_file,
+ lldb_private::CompilerType &record_type,
+ PDBFuncSymbolEnumerator &methods_enum);
+ clang::CXXMethodDecl *
+ AddRecordMethod(lldb_private::SymbolFile &symbol_file,
+ lldb_private::CompilerType &record_type,
+ const llvm::pdb::PDBSymbolFunc &method) const;
+
+ lldb_private::TypeSystemClang &m_ast;
+ lldb_private::ClangASTImporter m_ast_importer;
+
+ CXXRecordDeclToUidMap m_forward_decl_to_uid;
+ UidToDeclMap m_uid_to_decl;
+ ParentToNamespacesMap m_parent_to_namespaces;
+ NamespacesSet m_namespaces;
+ DeclContextToUidMap m_decl_context_to_uid;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_PDB_PDBASTPARSER_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp
new file mode 100644
index 000000000000..95add31385df
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp
@@ -0,0 +1,182 @@
+//===-- PDBLocationToDWARFExpression.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 "PDBLocationToDWARFExpression.h"
+
+#include "lldb/Core/Section.h"
+#include "lldb/Core/dwarf.h"
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/StreamBuffer.h"
+
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/PDB/IPDBSession.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
+
+#include "Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.h"
+#include "Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::npdb;
+using namespace lldb_private::dwarf;
+using namespace llvm::pdb;
+
+static std::unique_ptr<IPDBFrameData>
+GetCorrespondingFrameData(const IPDBSession &session,
+ const Variable::RangeList &ranges) {
+ auto enumFrameData = session.getFrameData();
+ if (!enumFrameData)
+ return nullptr;
+
+ std::unique_ptr<IPDBFrameData> found;
+ while (auto fd = enumFrameData->getNext()) {
+ Range<lldb::addr_t, lldb::addr_t> fdRange(fd->getVirtualAddress(),
+ fd->getLengthBlock());
+
+ for (size_t i = 0; i < ranges.GetSize(); i++) {
+ auto range = ranges.GetEntryAtIndex(i);
+ if (!range)
+ continue;
+
+ if (!range->DoesIntersect(fdRange))
+ continue;
+
+ found = std::move(fd);
+
+ break;
+ }
+ }
+
+ return found;
+}
+
+static bool EmitVFrameEvaluationDWARFExpression(
+ llvm::StringRef program, llvm::Triple::ArchType arch_type, Stream &stream) {
+ // VFrame value always stored in $TO pseudo-register
+ return TranslateFPOProgramToDWARFExpression(program, "$T0", arch_type,
+ stream);
+}
+
+DWARFExpression ConvertPDBLocationToDWARFExpression(
+ ModuleSP module, const PDBSymbolData &symbol,
+ const Variable::RangeList &ranges, bool &is_constant) {
+ is_constant = true;
+
+ if (!module)
+ return DWARFExpression();
+
+ const ArchSpec &architecture = module->GetArchitecture();
+ llvm::Triple::ArchType arch_type = architecture.GetMachine();
+ ByteOrder byte_order = architecture.GetByteOrder();
+ uint32_t address_size = architecture.GetAddressByteSize();
+ uint32_t byte_size = architecture.GetDataByteSize();
+ if (byte_order == eByteOrderInvalid || address_size == 0)
+ return DWARFExpression();
+
+ RegisterKind register_kind = eRegisterKindDWARF;
+ StreamBuffer<32> stream(Stream::eBinary, address_size, byte_order);
+ switch (symbol.getLocationType()) {
+ case PDB_LocType::Static:
+ case PDB_LocType::TLS: {
+ stream.PutHex8(DW_OP_addr);
+
+ SectionList *section_list = module->GetSectionList();
+ if (!section_list)
+ return DWARFExpression();
+
+ uint32_t section_id = symbol.getAddressSection();
+
+ auto section = section_list->FindSectionByID(section_id);
+ if (!section)
+ return DWARFExpression();
+
+ uint32_t offset = symbol.getAddressOffset();
+ stream.PutMaxHex64(section->GetFileAddress() + offset, address_size,
+ byte_order);
+
+ is_constant = false;
+
+ break;
+ }
+ case PDB_LocType::RegRel: {
+ uint32_t reg_num;
+ auto reg_id = symbol.getRegisterId();
+ if (reg_id == llvm::codeview::RegisterId::VFRAME) {
+ if (auto fd = GetCorrespondingFrameData(symbol.getSession(), ranges)) {
+ if (EmitVFrameEvaluationDWARFExpression(fd->getProgram(), arch_type,
+ stream)) {
+ int32_t offset = symbol.getOffset();
+ stream.PutHex8(DW_OP_consts);
+ stream.PutSLEB128(offset);
+ stream.PutHex8(DW_OP_plus);
+
+ register_kind = eRegisterKindLLDB;
+
+ is_constant = false;
+ break;
+ }
+ }
+
+ register_kind = eRegisterKindGeneric;
+ reg_num = LLDB_REGNUM_GENERIC_FP;
+ } else {
+ register_kind = eRegisterKindLLDB;
+ reg_num = GetLLDBRegisterNumber(arch_type, reg_id);
+ if (reg_num == LLDB_INVALID_REGNUM)
+ return DWARFExpression();
+ }
+
+ if (reg_num > 31) {
+ stream.PutHex8(DW_OP_bregx);
+ stream.PutULEB128(reg_num);
+ } else
+ stream.PutHex8(DW_OP_breg0 + reg_num);
+
+ int32_t offset = symbol.getOffset();
+ stream.PutSLEB128(offset);
+
+ is_constant = false;
+
+ break;
+ }
+ case PDB_LocType::Enregistered: {
+ register_kind = eRegisterKindLLDB;
+ uint32_t reg_num = GetLLDBRegisterNumber(arch_type, symbol.getRegisterId());
+ if (reg_num == LLDB_INVALID_REGNUM)
+ return DWARFExpression();
+
+ if (reg_num > 31) {
+ stream.PutHex8(DW_OP_regx);
+ stream.PutULEB128(reg_num);
+ } else
+ stream.PutHex8(DW_OP_reg0 + reg_num);
+
+ is_constant = false;
+
+ break;
+ }
+ case PDB_LocType::Constant: {
+ Variant value = symbol.getValue();
+ stream.PutRawBytes(&value.Value, sizeof(value.Value),
+ endian::InlHostByteOrder());
+ break;
+ }
+ default:
+ return DWARFExpression();
+ }
+
+ DataBufferSP buffer =
+ std::make_shared<DataBufferHeap>(stream.GetData(), stream.GetSize());
+ DataExtractor extractor(buffer, byte_order, address_size, byte_size);
+ DWARFExpression result(extractor);
+ result.SetRegisterKind(register_kind);
+
+ return result;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.h
new file mode 100644
index 000000000000..fd0fef03e2c8
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.h
@@ -0,0 +1,47 @@
+//===-- PDBLocationToDWARFExpression.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_PDB_PDBLOCATIONTODWARFEXPRESSION_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_PDB_PDBLOCATIONTODWARFEXPRESSION_H
+
+#include "lldb/Core/Module.h"
+#include "lldb/Symbol/Variable.h"
+
+namespace lldb_private {
+class DWARFExpression;
+}
+
+namespace llvm {
+namespace pdb {
+class PDBSymbolData;
+}
+} // namespace llvm
+
+/// Converts a location information from a PDB symbol to a DWARF expression
+///
+/// \param[in] module
+/// The module \a symbol belongs to.
+///
+/// \param[in] symbol
+/// The symbol with a location information to convert.
+///
+/// \param[in] ranges
+/// Ranges where this variable is valid.
+///
+/// \param[out] is_constant
+/// Set to \b true if the result expression is a constant value data,
+/// and \b false if it is a DWARF bytecode.
+///
+/// \return
+/// The DWARF expression corresponding to the location data of \a symbol.
+lldb_private::DWARFExpression
+ConvertPDBLocationToDWARFExpression(lldb::ModuleSP module,
+ const llvm::pdb::PDBSymbolData &symbol,
+ const lldb_private::Variable::RangeList &ranges,
+ bool &is_constant);
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
new file mode 100644
index 000000000000..9a282acae91f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
@@ -0,0 +1,2053 @@
+//===-- SymbolFilePDB.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 "SymbolFilePDB.h"
+
+#include "PDBASTParser.h"
+#include "PDBLocationToDWARFExpression.h"
+
+#include "clang/Lex/Lexer.h"
+
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/LineTable.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Symbol/TypeList.h"
+#include "lldb/Symbol/TypeMap.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegularExpression.h"
+
+#include "llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h"
+#include "llvm/DebugInfo/PDB/GenericError.h"
+#include "llvm/DebugInfo/PDB/IPDBDataStream.h"
+#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
+#include "llvm/DebugInfo/PDB/IPDBLineNumber.h"
+#include "llvm/DebugInfo/PDB/IPDBSectionContrib.h"
+#include "llvm/DebugInfo/PDB/IPDBSourceFile.h"
+#include "llvm/DebugInfo/PDB/IPDBTable.h"
+#include "llvm/DebugInfo/PDB/PDBSymbol.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolBlock.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
+
+#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
+#include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h"
+#include "Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h"
+
+#if defined(_WIN32)
+#include "llvm/Config/llvm-config.h"
+#include <optional>
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace llvm::pdb;
+
+LLDB_PLUGIN_DEFINE(SymbolFilePDB)
+
+char SymbolFilePDB::ID;
+
+namespace {
+lldb::LanguageType TranslateLanguage(PDB_Lang lang) {
+ switch (lang) {
+ case PDB_Lang::Cpp:
+ return lldb::LanguageType::eLanguageTypeC_plus_plus;
+ case PDB_Lang::C:
+ return lldb::LanguageType::eLanguageTypeC;
+ case PDB_Lang::Swift:
+ return lldb::LanguageType::eLanguageTypeSwift;
+ case PDB_Lang::Rust:
+ return lldb::LanguageType::eLanguageTypeRust;
+ case PDB_Lang::ObjC:
+ return lldb::LanguageType::eLanguageTypeObjC;
+ case PDB_Lang::ObjCpp:
+ return lldb::LanguageType::eLanguageTypeObjC_plus_plus;
+ default:
+ return lldb::LanguageType::eLanguageTypeUnknown;
+ }
+}
+
+bool ShouldAddLine(uint32_t requested_line, uint32_t actual_line,
+ uint32_t addr_length) {
+ return ((requested_line == 0 || actual_line == requested_line) &&
+ addr_length > 0);
+}
+} // namespace
+
+static bool ShouldUseNativeReader() {
+#if defined(_WIN32)
+#if LLVM_ENABLE_DIA_SDK
+ llvm::StringRef use_native = ::getenv("LLDB_USE_NATIVE_PDB_READER");
+ if (!use_native.equals_insensitive("on") &&
+ !use_native.equals_insensitive("yes") &&
+ !use_native.equals_insensitive("1") &&
+ !use_native.equals_insensitive("true"))
+ return false;
+#endif
+#endif
+ return true;
+}
+
+void SymbolFilePDB::Initialize() {
+ if (ShouldUseNativeReader()) {
+ npdb::SymbolFileNativePDB::Initialize();
+ } else {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(), CreateInstance,
+ DebuggerInitialize);
+ }
+}
+
+void SymbolFilePDB::Terminate() {
+ if (ShouldUseNativeReader()) {
+ npdb::SymbolFileNativePDB::Terminate();
+ } else {
+ PluginManager::UnregisterPlugin(CreateInstance);
+ }
+}
+
+void SymbolFilePDB::DebuggerInitialize(lldb_private::Debugger &debugger) {}
+
+llvm::StringRef SymbolFilePDB::GetPluginDescriptionStatic() {
+ return "Microsoft PDB debug symbol file reader.";
+}
+
+lldb_private::SymbolFile *
+SymbolFilePDB::CreateInstance(ObjectFileSP objfile_sp) {
+ return new SymbolFilePDB(std::move(objfile_sp));
+}
+
+SymbolFilePDB::SymbolFilePDB(lldb::ObjectFileSP objfile_sp)
+ : SymbolFileCommon(std::move(objfile_sp)), m_session_up(), m_global_scope_up() {}
+
+SymbolFilePDB::~SymbolFilePDB() = default;
+
+uint32_t SymbolFilePDB::CalculateAbilities() {
+ uint32_t abilities = 0;
+ if (!m_objfile_sp)
+ return 0;
+
+ if (!m_session_up) {
+ // Lazily load and match the PDB file, but only do this once.
+ std::string exePath = m_objfile_sp->GetFileSpec().GetPath();
+ auto error = loadDataForEXE(PDB_ReaderType::DIA, llvm::StringRef(exePath),
+ m_session_up);
+ if (error) {
+ llvm::consumeError(std::move(error));
+ auto module_sp = m_objfile_sp->GetModule();
+ if (!module_sp)
+ return 0;
+ // See if any symbol file is specified through `--symfile` option.
+ FileSpec symfile = module_sp->GetSymbolFileFileSpec();
+ if (!symfile)
+ return 0;
+ error = loadDataForPDB(PDB_ReaderType::DIA,
+ llvm::StringRef(symfile.GetPath()), m_session_up);
+ if (error) {
+ llvm::consumeError(std::move(error));
+ return 0;
+ }
+ }
+ }
+ if (!m_session_up)
+ return 0;
+
+ auto enum_tables_up = m_session_up->getEnumTables();
+ if (!enum_tables_up)
+ return 0;
+ while (auto table_up = enum_tables_up->getNext()) {
+ if (table_up->getItemCount() == 0)
+ continue;
+ auto type = table_up->getTableType();
+ switch (type) {
+ case PDB_TableType::Symbols:
+ // This table represents a store of symbols with types listed in
+ // PDBSym_Type
+ abilities |= (CompileUnits | Functions | Blocks | GlobalVariables |
+ LocalVariables | VariableTypes);
+ break;
+ case PDB_TableType::LineNumbers:
+ abilities |= LineTables;
+ break;
+ default:
+ break;
+ }
+ }
+ return abilities;
+}
+
+void SymbolFilePDB::InitializeObject() {
+ lldb::addr_t obj_load_address =
+ m_objfile_sp->GetBaseAddress().GetFileAddress();
+ lldbassert(obj_load_address && obj_load_address != LLDB_INVALID_ADDRESS);
+ m_session_up->setLoadAddress(obj_load_address);
+ if (!m_global_scope_up)
+ m_global_scope_up = m_session_up->getGlobalScope();
+ lldbassert(m_global_scope_up.get());
+}
+
+uint32_t SymbolFilePDB::CalculateNumCompileUnits() {
+ auto compilands = m_global_scope_up->findAllChildren<PDBSymbolCompiland>();
+ if (!compilands)
+ return 0;
+
+ // The linker could link *.dll (compiland language = LINK), or import
+ // *.dll. For example, a compiland with name `Import:KERNEL32.dll` could be
+ // found as a child of the global scope (PDB executable). Usually, such
+ // compilands contain `thunk` symbols in which we are not interested for
+ // now. However we still count them in the compiland list. If we perform
+ // any compiland related activity, like finding symbols through
+ // llvm::pdb::IPDBSession methods, such compilands will all be searched
+ // automatically no matter whether we include them or not.
+ uint32_t compile_unit_count = compilands->getChildCount();
+
+ // The linker can inject an additional "dummy" compilation unit into the
+ // PDB. Ignore this special compile unit for our purposes, if it is there.
+ // It is always the last one.
+ auto last_compiland_up = compilands->getChildAtIndex(compile_unit_count - 1);
+ lldbassert(last_compiland_up.get());
+ std::string name = last_compiland_up->getName();
+ if (name == "* Linker *")
+ --compile_unit_count;
+ return compile_unit_count;
+}
+
+void SymbolFilePDB::GetCompileUnitIndex(
+ const llvm::pdb::PDBSymbolCompiland &pdb_compiland, uint32_t &index) {
+ auto results_up = m_global_scope_up->findAllChildren<PDBSymbolCompiland>();
+ if (!results_up)
+ return;
+ auto uid = pdb_compiland.getSymIndexId();
+ for (uint32_t cu_idx = 0; cu_idx < GetNumCompileUnits(); ++cu_idx) {
+ auto compiland_up = results_up->getChildAtIndex(cu_idx);
+ if (!compiland_up)
+ continue;
+ if (compiland_up->getSymIndexId() == uid) {
+ index = cu_idx;
+ return;
+ }
+ }
+ index = UINT32_MAX;
+}
+
+std::unique_ptr<llvm::pdb::PDBSymbolCompiland>
+SymbolFilePDB::GetPDBCompilandByUID(uint32_t uid) {
+ return m_session_up->getConcreteSymbolById<PDBSymbolCompiland>(uid);
+}
+
+lldb::CompUnitSP SymbolFilePDB::ParseCompileUnitAtIndex(uint32_t index) {
+ if (index >= GetNumCompileUnits())
+ return CompUnitSP();
+
+ // Assuming we always retrieve same compilands listed in same order through
+ // `PDBSymbolExe::findAllChildren` method, otherwise using `index` to get a
+ // compile unit makes no sense.
+ auto results = m_global_scope_up->findAllChildren<PDBSymbolCompiland>();
+ if (!results)
+ return CompUnitSP();
+ auto compiland_up = results->getChildAtIndex(index);
+ if (!compiland_up)
+ return CompUnitSP();
+ return ParseCompileUnitForUID(compiland_up->getSymIndexId(), index);
+}
+
+lldb::LanguageType SymbolFilePDB::ParseLanguage(CompileUnit &comp_unit) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ auto compiland_up = GetPDBCompilandByUID(comp_unit.GetID());
+ if (!compiland_up)
+ return lldb::eLanguageTypeUnknown;
+ auto details = compiland_up->findOneChild<PDBSymbolCompilandDetails>();
+ if (!details)
+ return lldb::eLanguageTypeUnknown;
+ return TranslateLanguage(details->getLanguage());
+}
+
+lldb_private::Function *
+SymbolFilePDB::ParseCompileUnitFunctionForPDBFunc(const PDBSymbolFunc &pdb_func,
+ CompileUnit &comp_unit) {
+ if (FunctionSP result = comp_unit.FindFunctionByUID(pdb_func.getSymIndexId()))
+ return result.get();
+
+ auto file_vm_addr = pdb_func.getVirtualAddress();
+ if (file_vm_addr == LLDB_INVALID_ADDRESS || file_vm_addr == 0)
+ return nullptr;
+
+ auto func_length = pdb_func.getLength();
+ AddressRange func_range =
+ AddressRange(file_vm_addr, func_length,
+ GetObjectFile()->GetModule()->GetSectionList());
+ if (!func_range.GetBaseAddress().IsValid())
+ return nullptr;
+
+ lldb_private::Type *func_type = ResolveTypeUID(pdb_func.getSymIndexId());
+ if (!func_type)
+ return nullptr;
+
+ user_id_t func_type_uid = pdb_func.getSignatureId();
+
+ Mangled mangled = GetMangledForPDBFunc(pdb_func);
+
+ FunctionSP func_sp =
+ std::make_shared<Function>(&comp_unit, pdb_func.getSymIndexId(),
+ func_type_uid, mangled, func_type, func_range);
+
+ comp_unit.AddFunction(func_sp);
+
+ LanguageType lang = ParseLanguage(comp_unit);
+ auto type_system_or_err = GetTypeSystemForLanguage(lang);
+ if (auto err = type_system_or_err.takeError()) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Symbols), std::move(err),
+ "Unable to parse PDBFunc: {0}");
+ return nullptr;
+ }
+
+ auto ts = *type_system_or_err;
+ TypeSystemClang *clang_type_system =
+ llvm::dyn_cast_or_null<TypeSystemClang>(ts.get());
+ if (!clang_type_system)
+ return nullptr;
+ clang_type_system->GetPDBParser()->GetDeclForSymbol(pdb_func);
+
+ return func_sp.get();
+}
+
+size_t SymbolFilePDB::ParseFunctions(CompileUnit &comp_unit) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ size_t func_added = 0;
+ auto compiland_up = GetPDBCompilandByUID(comp_unit.GetID());
+ if (!compiland_up)
+ return 0;
+ auto results_up = compiland_up->findAllChildren<PDBSymbolFunc>();
+ if (!results_up)
+ return 0;
+ while (auto pdb_func_up = results_up->getNext()) {
+ auto func_sp = comp_unit.FindFunctionByUID(pdb_func_up->getSymIndexId());
+ if (!func_sp) {
+ if (ParseCompileUnitFunctionForPDBFunc(*pdb_func_up, comp_unit))
+ ++func_added;
+ }
+ }
+ return func_added;
+}
+
+bool SymbolFilePDB::ParseLineTable(CompileUnit &comp_unit) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ if (comp_unit.GetLineTable())
+ return true;
+ return ParseCompileUnitLineTable(comp_unit, 0);
+}
+
+bool SymbolFilePDB::ParseDebugMacros(CompileUnit &comp_unit) {
+ // PDB doesn't contain information about macros
+ return false;
+}
+
+bool SymbolFilePDB::ParseSupportFiles(
+ CompileUnit &comp_unit, lldb_private::SupportFileList &support_files) {
+
+ // In theory this is unnecessary work for us, because all of this information
+ // is easily (and quickly) accessible from DebugInfoPDB, so caching it a
+ // second time seems like a waste. Unfortunately, there's no good way around
+ // this short of a moderate refactor since SymbolVendor depends on being able
+ // to cache this list.
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ auto compiland_up = GetPDBCompilandByUID(comp_unit.GetID());
+ if (!compiland_up)
+ return false;
+ auto files = m_session_up->getSourceFilesForCompiland(*compiland_up);
+ if (!files || files->getChildCount() == 0)
+ return false;
+
+ while (auto file = files->getNext()) {
+ FileSpec spec(file->getFileName(), FileSpec::Style::windows);
+ support_files.AppendIfUnique(spec);
+ }
+
+ return true;
+}
+
+bool SymbolFilePDB::ParseImportedModules(
+ const lldb_private::SymbolContext &sc,
+ std::vector<SourceModule> &imported_modules) {
+ // PDB does not yet support module debug info
+ return false;
+}
+
+static size_t ParseFunctionBlocksForPDBSymbol(
+ uint64_t func_file_vm_addr, const llvm::pdb::PDBSymbol *pdb_symbol,
+ lldb_private::Block *parent_block, bool is_top_parent) {
+ assert(pdb_symbol && parent_block);
+
+ size_t num_added = 0;
+ switch (pdb_symbol->getSymTag()) {
+ case PDB_SymType::Block:
+ case PDB_SymType::Function: {
+ Block *block = nullptr;
+ auto &raw_sym = pdb_symbol->getRawSymbol();
+ if (auto *pdb_func = llvm::dyn_cast<PDBSymbolFunc>(pdb_symbol)) {
+ if (pdb_func->hasNoInlineAttribute())
+ break;
+ if (is_top_parent)
+ block = parent_block;
+ else
+ break;
+ } else if (llvm::isa<PDBSymbolBlock>(pdb_symbol)) {
+ auto uid = pdb_symbol->getSymIndexId();
+ if (parent_block->FindBlockByID(uid))
+ break;
+ if (raw_sym.getVirtualAddress() < func_file_vm_addr)
+ break;
+
+ auto block_sp = std::make_shared<Block>(pdb_symbol->getSymIndexId());
+ parent_block->AddChild(block_sp);
+ block = block_sp.get();
+ } else
+ llvm_unreachable("Unexpected PDB symbol!");
+
+ block->AddRange(Block::Range(
+ raw_sym.getVirtualAddress() - func_file_vm_addr, raw_sym.getLength()));
+ block->FinalizeRanges();
+ ++num_added;
+
+ auto results_up = pdb_symbol->findAllChildren();
+ if (!results_up)
+ break;
+ while (auto symbol_up = results_up->getNext()) {
+ num_added += ParseFunctionBlocksForPDBSymbol(
+ func_file_vm_addr, symbol_up.get(), block, false);
+ }
+ } break;
+ default:
+ break;
+ }
+ return num_added;
+}
+
+size_t SymbolFilePDB::ParseBlocksRecursive(Function &func) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ size_t num_added = 0;
+ auto uid = func.GetID();
+ auto pdb_func_up = m_session_up->getConcreteSymbolById<PDBSymbolFunc>(uid);
+ if (!pdb_func_up)
+ return 0;
+ Block &parent_block = func.GetBlock(false);
+ num_added = ParseFunctionBlocksForPDBSymbol(
+ pdb_func_up->getVirtualAddress(), pdb_func_up.get(), &parent_block, true);
+ return num_added;
+}
+
+size_t SymbolFilePDB::ParseTypes(CompileUnit &comp_unit) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+
+ size_t num_added = 0;
+ auto compiland = GetPDBCompilandByUID(comp_unit.GetID());
+ if (!compiland)
+ return 0;
+
+ auto ParseTypesByTagFn = [&num_added, this](const PDBSymbol &raw_sym) {
+ std::unique_ptr<IPDBEnumSymbols> results;
+ PDB_SymType tags_to_search[] = {PDB_SymType::Enum, PDB_SymType::Typedef,
+ PDB_SymType::UDT};
+ for (auto tag : tags_to_search) {
+ results = raw_sym.findAllChildren(tag);
+ if (!results || results->getChildCount() == 0)
+ continue;
+ while (auto symbol = results->getNext()) {
+ switch (symbol->getSymTag()) {
+ case PDB_SymType::Enum:
+ case PDB_SymType::UDT:
+ case PDB_SymType::Typedef:
+ break;
+ default:
+ continue;
+ }
+
+ // This should cause the type to get cached and stored in the `m_types`
+ // lookup.
+ if (auto type = ResolveTypeUID(symbol->getSymIndexId())) {
+ // Resolve the type completely to avoid a completion
+ // (and so a list change, which causes an iterators invalidation)
+ // during a TypeList dumping
+ type->GetFullCompilerType();
+ ++num_added;
+ }
+ }
+ }
+ };
+
+ ParseTypesByTagFn(*compiland);
+
+ // Also parse global types particularly coming from this compiland.
+ // Unfortunately, PDB has no compiland information for each global type. We
+ // have to parse them all. But ensure we only do this once.
+ static bool parse_all_global_types = false;
+ if (!parse_all_global_types) {
+ ParseTypesByTagFn(*m_global_scope_up);
+ parse_all_global_types = true;
+ }
+ return num_added;
+}
+
+size_t
+SymbolFilePDB::ParseVariablesForContext(const lldb_private::SymbolContext &sc) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ if (!sc.comp_unit)
+ return 0;
+
+ size_t num_added = 0;
+ if (sc.function) {
+ auto pdb_func = m_session_up->getConcreteSymbolById<PDBSymbolFunc>(
+ sc.function->GetID());
+ if (!pdb_func)
+ return 0;
+
+ num_added += ParseVariables(sc, *pdb_func);
+ sc.function->GetBlock(false).SetDidParseVariables(true, true);
+ } else if (sc.comp_unit) {
+ auto compiland = GetPDBCompilandByUID(sc.comp_unit->GetID());
+ if (!compiland)
+ return 0;
+
+ if (sc.comp_unit->GetVariableList(false))
+ return 0;
+
+ auto results = m_global_scope_up->findAllChildren<PDBSymbolData>();
+ if (results && results->getChildCount()) {
+ while (auto result = results->getNext()) {
+ auto cu_id = GetCompilandId(*result);
+ // FIXME: We are not able to determine variable's compile unit.
+ if (cu_id == 0)
+ continue;
+
+ if (cu_id == sc.comp_unit->GetID())
+ num_added += ParseVariables(sc, *result);
+ }
+ }
+
+ // FIXME: A `file static` or `global constant` variable appears both in
+ // compiland's children and global scope's children with unexpectedly
+ // different symbol's Id making it ambiguous.
+
+ // FIXME: 'local constant', for example, const char var[] = "abc", declared
+ // in a function scope, can't be found in PDB.
+
+ // Parse variables in this compiland.
+ num_added += ParseVariables(sc, *compiland);
+ }
+
+ return num_added;
+}
+
+lldb_private::Type *SymbolFilePDB::ResolveTypeUID(lldb::user_id_t type_uid) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ auto find_result = m_types.find(type_uid);
+ if (find_result != m_types.end())
+ return find_result->second.get();
+
+ auto type_system_or_err =
+ GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
+ if (auto err = type_system_or_err.takeError()) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Symbols), std::move(err),
+ "Unable to ResolveTypeUID: {0}");
+ return nullptr;
+ }
+
+ auto ts = *type_system_or_err;
+ TypeSystemClang *clang_type_system =
+ llvm::dyn_cast_or_null<TypeSystemClang>(ts.get());
+ if (!clang_type_system)
+ return nullptr;
+ PDBASTParser *pdb = clang_type_system->GetPDBParser();
+ if (!pdb)
+ return nullptr;
+
+ auto pdb_type = m_session_up->getSymbolById(type_uid);
+ if (pdb_type == nullptr)
+ return nullptr;
+
+ lldb::TypeSP result = pdb->CreateLLDBTypeFromPDBType(*pdb_type);
+ if (result) {
+ m_types.insert(std::make_pair(type_uid, result));
+ }
+ return result.get();
+}
+
+std::optional<SymbolFile::ArrayInfo> SymbolFilePDB::GetDynamicArrayInfoForUID(
+ lldb::user_id_t type_uid, const lldb_private::ExecutionContext *exe_ctx) {
+ return std::nullopt;
+}
+
+bool SymbolFilePDB::CompleteType(lldb_private::CompilerType &compiler_type) {
+ std::lock_guard<std::recursive_mutex> guard(
+ GetObjectFile()->GetModule()->GetMutex());
+
+ auto type_system_or_err =
+ GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
+ if (auto err = type_system_or_err.takeError()) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Symbols), std::move(err),
+ "Unable to get dynamic array info for UID: {0}");
+ return false;
+ }
+ auto ts = *type_system_or_err;
+ TypeSystemClang *clang_ast_ctx =
+ llvm::dyn_cast_or_null<TypeSystemClang>(ts.get());
+
+ if (!clang_ast_ctx)
+ return false;
+
+ PDBASTParser *pdb = clang_ast_ctx->GetPDBParser();
+ if (!pdb)
+ return false;
+
+ return pdb->CompleteTypeFromPDB(compiler_type);
+}
+
+lldb_private::CompilerDecl SymbolFilePDB::GetDeclForUID(lldb::user_id_t uid) {
+ auto type_system_or_err =
+ GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
+ if (auto err = type_system_or_err.takeError()) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Symbols), std::move(err),
+ "Unable to get decl for UID: {0}");
+ return CompilerDecl();
+ }
+ auto ts = *type_system_or_err;
+ TypeSystemClang *clang_ast_ctx =
+ llvm::dyn_cast_or_null<TypeSystemClang>(ts.get());
+ if (!clang_ast_ctx)
+ return CompilerDecl();
+
+ PDBASTParser *pdb = clang_ast_ctx->GetPDBParser();
+ if (!pdb)
+ return CompilerDecl();
+
+ auto symbol = m_session_up->getSymbolById(uid);
+ if (!symbol)
+ return CompilerDecl();
+
+ auto decl = pdb->GetDeclForSymbol(*symbol);
+ if (!decl)
+ return CompilerDecl();
+
+ return clang_ast_ctx->GetCompilerDecl(decl);
+}
+
+lldb_private::CompilerDeclContext
+SymbolFilePDB::GetDeclContextForUID(lldb::user_id_t uid) {
+ auto type_system_or_err =
+ GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
+ if (auto err = type_system_or_err.takeError()) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Symbols), std::move(err),
+ "Unable to get DeclContext for UID: {0}");
+ return CompilerDeclContext();
+ }
+
+ auto ts = *type_system_or_err;
+ TypeSystemClang *clang_ast_ctx =
+ llvm::dyn_cast_or_null<TypeSystemClang>(ts.get());
+ if (!clang_ast_ctx)
+ return CompilerDeclContext();
+
+ PDBASTParser *pdb = clang_ast_ctx->GetPDBParser();
+ if (!pdb)
+ return CompilerDeclContext();
+
+ auto symbol = m_session_up->getSymbolById(uid);
+ if (!symbol)
+ return CompilerDeclContext();
+
+ auto decl_context = pdb->GetDeclContextForSymbol(*symbol);
+ if (!decl_context)
+ return GetDeclContextContainingUID(uid);
+
+ return clang_ast_ctx->CreateDeclContext(decl_context);
+}
+
+lldb_private::CompilerDeclContext
+SymbolFilePDB::GetDeclContextContainingUID(lldb::user_id_t uid) {
+ auto type_system_or_err =
+ GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
+ if (auto err = type_system_or_err.takeError()) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Symbols), std::move(err),
+ "Unable to get DeclContext containing UID: {0}");
+ return CompilerDeclContext();
+ }
+
+ auto ts = *type_system_or_err;
+ TypeSystemClang *clang_ast_ctx =
+ llvm::dyn_cast_or_null<TypeSystemClang>(ts.get());
+ if (!clang_ast_ctx)
+ return CompilerDeclContext();
+
+ PDBASTParser *pdb = clang_ast_ctx->GetPDBParser();
+ if (!pdb)
+ return CompilerDeclContext();
+
+ auto symbol = m_session_up->getSymbolById(uid);
+ if (!symbol)
+ return CompilerDeclContext();
+
+ auto decl_context = pdb->GetDeclContextContainingSymbol(*symbol);
+ assert(decl_context);
+
+ return clang_ast_ctx->CreateDeclContext(decl_context);
+}
+
+void SymbolFilePDB::ParseDeclsForContext(
+ lldb_private::CompilerDeclContext decl_ctx) {
+ auto type_system_or_err =
+ GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
+ if (auto err = type_system_or_err.takeError()) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Symbols), std::move(err),
+ "Unable to parse decls for context: {0}");
+ return;
+ }
+
+ auto ts = *type_system_or_err;
+ TypeSystemClang *clang_ast_ctx =
+ llvm::dyn_cast_or_null<TypeSystemClang>(ts.get());
+ if (!clang_ast_ctx)
+ return;
+
+ PDBASTParser *pdb = clang_ast_ctx->GetPDBParser();
+ if (!pdb)
+ return;
+
+ pdb->ParseDeclsForDeclContext(
+ static_cast<clang::DeclContext *>(decl_ctx.GetOpaqueDeclContext()));
+}
+
+uint32_t
+SymbolFilePDB::ResolveSymbolContext(const lldb_private::Address &so_addr,
+ SymbolContextItem resolve_scope,
+ lldb_private::SymbolContext &sc) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ uint32_t resolved_flags = 0;
+ if (resolve_scope & eSymbolContextCompUnit ||
+ resolve_scope & eSymbolContextVariable ||
+ resolve_scope & eSymbolContextFunction ||
+ resolve_scope & eSymbolContextBlock ||
+ resolve_scope & eSymbolContextLineEntry) {
+ auto cu_sp = GetCompileUnitContainsAddress(so_addr);
+ if (!cu_sp) {
+ if (resolved_flags & eSymbolContextVariable) {
+ // TODO: Resolve variables
+ }
+ return 0;
+ }
+ sc.comp_unit = cu_sp.get();
+ resolved_flags |= eSymbolContextCompUnit;
+ lldbassert(sc.module_sp == cu_sp->GetModule());
+ }
+
+ if (resolve_scope & eSymbolContextFunction ||
+ resolve_scope & eSymbolContextBlock) {
+ addr_t file_vm_addr = so_addr.GetFileAddress();
+ auto symbol_up =
+ m_session_up->findSymbolByAddress(file_vm_addr, PDB_SymType::Function);
+ if (symbol_up) {
+ auto *pdb_func = llvm::dyn_cast<PDBSymbolFunc>(symbol_up.get());
+ assert(pdb_func);
+ auto func_uid = pdb_func->getSymIndexId();
+ sc.function = sc.comp_unit->FindFunctionByUID(func_uid).get();
+ if (sc.function == nullptr)
+ sc.function =
+ ParseCompileUnitFunctionForPDBFunc(*pdb_func, *sc.comp_unit);
+ if (sc.function) {
+ resolved_flags |= eSymbolContextFunction;
+ if (resolve_scope & eSymbolContextBlock) {
+ auto block_symbol = m_session_up->findSymbolByAddress(
+ file_vm_addr, PDB_SymType::Block);
+ auto block_id = block_symbol ? block_symbol->getSymIndexId()
+ : sc.function->GetID();
+ sc.block = sc.function->GetBlock(true).FindBlockByID(block_id);
+ if (sc.block)
+ resolved_flags |= eSymbolContextBlock;
+ }
+ }
+ }
+ }
+
+ if (resolve_scope & eSymbolContextLineEntry) {
+ if (auto *line_table = sc.comp_unit->GetLineTable()) {
+ Address addr(so_addr);
+ if (line_table->FindLineEntryByAddress(addr, sc.line_entry))
+ resolved_flags |= eSymbolContextLineEntry;
+ }
+ }
+
+ return resolved_flags;
+}
+
+uint32_t SymbolFilePDB::ResolveSymbolContext(
+ const lldb_private::SourceLocationSpec &src_location_spec,
+ SymbolContextItem resolve_scope, lldb_private::SymbolContextList &sc_list) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ const size_t old_size = sc_list.GetSize();
+ const FileSpec &file_spec = src_location_spec.GetFileSpec();
+ const uint32_t line = src_location_spec.GetLine().value_or(0);
+ if (resolve_scope & lldb::eSymbolContextCompUnit) {
+ // Locate all compilation units with line numbers referencing the specified
+ // file. For example, if `file_spec` is <vector>, then this should return
+ // all source files and header files that reference <vector>, either
+ // directly or indirectly.
+ auto compilands = m_session_up->findCompilandsForSourceFile(
+ file_spec.GetPath(), PDB_NameSearchFlags::NS_CaseInsensitive);
+
+ if (!compilands)
+ return 0;
+
+ // For each one, either find its previously parsed data or parse it afresh
+ // and add it to the symbol context list.
+ while (auto compiland = compilands->getNext()) {
+ // If we're not checking inlines, then don't add line information for
+ // this file unless the FileSpec matches. For inline functions, we don't
+ // have to match the FileSpec since they could be defined in headers
+ // other than file specified in FileSpec.
+ if (!src_location_spec.GetCheckInlines()) {
+ std::string source_file = compiland->getSourceFileFullPath();
+ if (source_file.empty())
+ continue;
+ FileSpec this_spec(source_file, FileSpec::Style::windows);
+ bool need_full_match = !file_spec.GetDirectory().IsEmpty();
+ if (FileSpec::Compare(file_spec, this_spec, need_full_match) != 0)
+ continue;
+ }
+
+ SymbolContext sc;
+ auto cu = ParseCompileUnitForUID(compiland->getSymIndexId());
+ if (!cu)
+ continue;
+ sc.comp_unit = cu.get();
+ sc.module_sp = cu->GetModule();
+
+ // If we were asked to resolve line entries, add all entries to the line
+ // table that match the requested line (or all lines if `line` == 0).
+ if (resolve_scope & (eSymbolContextFunction | eSymbolContextBlock |
+ eSymbolContextLineEntry)) {
+ bool has_line_table = ParseCompileUnitLineTable(*sc.comp_unit, line);
+
+ if ((resolve_scope & eSymbolContextLineEntry) && !has_line_table) {
+ // The query asks for line entries, but we can't get them for the
+ // compile unit. This is not normal for `line` = 0. So just assert
+ // it.
+ assert(line && "Couldn't get all line entries!\n");
+
+ // Current compiland does not have the requested line. Search next.
+ continue;
+ }
+
+ if (resolve_scope & (eSymbolContextFunction | eSymbolContextBlock)) {
+ if (!has_line_table)
+ continue;
+
+ auto *line_table = sc.comp_unit->GetLineTable();
+ lldbassert(line_table);
+
+ uint32_t num_line_entries = line_table->GetSize();
+ // Skip the terminal line entry.
+ --num_line_entries;
+
+ // If `line `!= 0, see if we can resolve function for each line entry
+ // in the line table.
+ for (uint32_t line_idx = 0; line && line_idx < num_line_entries;
+ ++line_idx) {
+ if (!line_table->GetLineEntryAtIndex(line_idx, sc.line_entry))
+ continue;
+
+ auto file_vm_addr =
+ sc.line_entry.range.GetBaseAddress().GetFileAddress();
+ if (file_vm_addr == LLDB_INVALID_ADDRESS || file_vm_addr == 0)
+ continue;
+
+ auto symbol_up = m_session_up->findSymbolByAddress(
+ file_vm_addr, PDB_SymType::Function);
+ if (symbol_up) {
+ auto func_uid = symbol_up->getSymIndexId();
+ sc.function = sc.comp_unit->FindFunctionByUID(func_uid).get();
+ if (sc.function == nullptr) {
+ auto pdb_func = llvm::dyn_cast<PDBSymbolFunc>(symbol_up.get());
+ assert(pdb_func);
+ sc.function = ParseCompileUnitFunctionForPDBFunc(*pdb_func,
+ *sc.comp_unit);
+ }
+ if (sc.function && (resolve_scope & eSymbolContextBlock)) {
+ Block &block = sc.function->GetBlock(true);
+ sc.block = block.FindBlockByID(sc.function->GetID());
+ }
+ }
+ sc_list.Append(sc);
+ }
+ } else if (has_line_table) {
+ // We can parse line table for the compile unit. But no query to
+ // resolve function or block. We append `sc` to the list anyway.
+ sc_list.Append(sc);
+ }
+ } else {
+ // No query for line entry, function or block. But we have a valid
+ // compile unit, append `sc` to the list.
+ sc_list.Append(sc);
+ }
+ }
+ }
+ return sc_list.GetSize() - old_size;
+}
+
+std::string SymbolFilePDB::GetMangledForPDBData(const PDBSymbolData &pdb_data) {
+ // Cache public names at first
+ if (m_public_names.empty())
+ if (auto result_up =
+ m_global_scope_up->findAllChildren(PDB_SymType::PublicSymbol))
+ while (auto symbol_up = result_up->getNext())
+ if (auto addr = symbol_up->getRawSymbol().getVirtualAddress())
+ m_public_names[addr] = symbol_up->getRawSymbol().getName();
+
+ // Look up the name in the cache
+ return m_public_names.lookup(pdb_data.getVirtualAddress());
+}
+
+VariableSP SymbolFilePDB::ParseVariableForPDBData(
+ const lldb_private::SymbolContext &sc,
+ const llvm::pdb::PDBSymbolData &pdb_data) {
+ VariableSP var_sp;
+ uint32_t var_uid = pdb_data.getSymIndexId();
+ auto result = m_variables.find(var_uid);
+ if (result != m_variables.end())
+ return result->second;
+
+ ValueType scope = eValueTypeInvalid;
+ bool is_static_member = false;
+ bool is_external = false;
+ bool is_artificial = false;
+
+ switch (pdb_data.getDataKind()) {
+ case PDB_DataKind::Global:
+ scope = eValueTypeVariableGlobal;
+ is_external = true;
+ break;
+ case PDB_DataKind::Local:
+ scope = eValueTypeVariableLocal;
+ break;
+ case PDB_DataKind::FileStatic:
+ scope = eValueTypeVariableStatic;
+ break;
+ case PDB_DataKind::StaticMember:
+ is_static_member = true;
+ scope = eValueTypeVariableStatic;
+ break;
+ case PDB_DataKind::Member:
+ scope = eValueTypeVariableStatic;
+ break;
+ case PDB_DataKind::Param:
+ scope = eValueTypeVariableArgument;
+ break;
+ case PDB_DataKind::Constant:
+ scope = eValueTypeConstResult;
+ break;
+ default:
+ break;
+ }
+
+ switch (pdb_data.getLocationType()) {
+ case PDB_LocType::TLS:
+ scope = eValueTypeVariableThreadLocal;
+ break;
+ case PDB_LocType::RegRel: {
+ // It is a `this` pointer.
+ if (pdb_data.getDataKind() == PDB_DataKind::ObjectPtr) {
+ scope = eValueTypeVariableArgument;
+ is_artificial = true;
+ }
+ } break;
+ default:
+ break;
+ }
+
+ Declaration decl;
+ if (!is_artificial && !pdb_data.isCompilerGenerated()) {
+ if (auto lines = pdb_data.getLineNumbers()) {
+ if (auto first_line = lines->getNext()) {
+ uint32_t src_file_id = first_line->getSourceFileId();
+ auto src_file = m_session_up->getSourceFileById(src_file_id);
+ if (src_file) {
+ FileSpec spec(src_file->getFileName());
+ decl.SetFile(spec);
+ decl.SetColumn(first_line->getColumnNumber());
+ decl.SetLine(first_line->getLineNumber());
+ }
+ }
+ }
+ }
+
+ Variable::RangeList ranges;
+ SymbolContextScope *context_scope = sc.comp_unit;
+ if (scope == eValueTypeVariableLocal || scope == eValueTypeVariableArgument) {
+ if (sc.function) {
+ Block &function_block = sc.function->GetBlock(true);
+ Block *block =
+ function_block.FindBlockByID(pdb_data.getLexicalParentId());
+ if (!block)
+ block = &function_block;
+
+ context_scope = block;
+
+ for (size_t i = 0, num_ranges = block->GetNumRanges(); i < num_ranges;
+ ++i) {
+ AddressRange range;
+ if (!block->GetRangeAtIndex(i, range))
+ continue;
+
+ ranges.Append(range.GetBaseAddress().GetFileAddress(),
+ range.GetByteSize());
+ }
+ }
+ }
+
+ SymbolFileTypeSP type_sp =
+ std::make_shared<SymbolFileType>(*this, pdb_data.getTypeId());
+
+ auto var_name = pdb_data.getName();
+ auto mangled = GetMangledForPDBData(pdb_data);
+ auto mangled_cstr = mangled.empty() ? nullptr : mangled.c_str();
+
+ bool is_constant;
+ ModuleSP module_sp = GetObjectFile()->GetModule();
+ DWARFExpressionList location(module_sp,
+ ConvertPDBLocationToDWARFExpression(
+ module_sp, pdb_data, ranges, is_constant),
+ nullptr);
+
+ var_sp = std::make_shared<Variable>(
+ var_uid, var_name.c_str(), mangled_cstr, type_sp, scope, context_scope,
+ ranges, &decl, location, is_external, is_artificial, is_constant,
+ is_static_member);
+
+ m_variables.insert(std::make_pair(var_uid, var_sp));
+ return var_sp;
+}
+
+size_t
+SymbolFilePDB::ParseVariables(const lldb_private::SymbolContext &sc,
+ const llvm::pdb::PDBSymbol &pdb_symbol,
+ lldb_private::VariableList *variable_list) {
+ size_t num_added = 0;
+
+ if (auto pdb_data = llvm::dyn_cast<PDBSymbolData>(&pdb_symbol)) {
+ VariableListSP local_variable_list_sp;
+
+ auto result = m_variables.find(pdb_data->getSymIndexId());
+ if (result != m_variables.end()) {
+ if (variable_list)
+ variable_list->AddVariableIfUnique(result->second);
+ } else {
+ // Prepare right VariableList for this variable.
+ if (auto lexical_parent = pdb_data->getLexicalParent()) {
+ switch (lexical_parent->getSymTag()) {
+ case PDB_SymType::Exe:
+ assert(sc.comp_unit);
+ [[fallthrough]];
+ case PDB_SymType::Compiland: {
+ if (sc.comp_unit) {
+ local_variable_list_sp = sc.comp_unit->GetVariableList(false);
+ if (!local_variable_list_sp) {
+ local_variable_list_sp = std::make_shared<VariableList>();
+ sc.comp_unit->SetVariableList(local_variable_list_sp);
+ }
+ }
+ } break;
+ case PDB_SymType::Block:
+ case PDB_SymType::Function: {
+ if (sc.function) {
+ Block *block = sc.function->GetBlock(true).FindBlockByID(
+ lexical_parent->getSymIndexId());
+ if (block) {
+ local_variable_list_sp = block->GetBlockVariableList(false);
+ if (!local_variable_list_sp) {
+ local_variable_list_sp = std::make_shared<VariableList>();
+ block->SetVariableList(local_variable_list_sp);
+ }
+ }
+ }
+ } break;
+ default:
+ break;
+ }
+ }
+
+ if (local_variable_list_sp) {
+ if (auto var_sp = ParseVariableForPDBData(sc, *pdb_data)) {
+ local_variable_list_sp->AddVariableIfUnique(var_sp);
+ if (variable_list)
+ variable_list->AddVariableIfUnique(var_sp);
+ ++num_added;
+ PDBASTParser *ast = GetPDBAstParser();
+ if (ast)
+ ast->GetDeclForSymbol(*pdb_data);
+ }
+ }
+ }
+ }
+
+ if (auto results = pdb_symbol.findAllChildren()) {
+ while (auto result = results->getNext())
+ num_added += ParseVariables(sc, *result, variable_list);
+ }
+
+ return num_added;
+}
+
+void SymbolFilePDB::FindGlobalVariables(
+ lldb_private::ConstString name, const CompilerDeclContext &parent_decl_ctx,
+ uint32_t max_matches, lldb_private::VariableList &variables) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx))
+ return;
+ if (name.IsEmpty())
+ return;
+
+ auto results = m_global_scope_up->findAllChildren<PDBSymbolData>();
+ if (!results)
+ return;
+
+ uint32_t matches = 0;
+ size_t old_size = variables.GetSize();
+ while (auto result = results->getNext()) {
+ auto pdb_data = llvm::dyn_cast<PDBSymbolData>(result.get());
+ if (max_matches > 0 && matches >= max_matches)
+ break;
+
+ SymbolContext sc;
+ sc.module_sp = m_objfile_sp->GetModule();
+ lldbassert(sc.module_sp.get());
+
+ if (name.GetStringRef() !=
+ MSVCUndecoratedNameParser::DropScope(pdb_data->getName()))
+ continue;
+
+ sc.comp_unit = ParseCompileUnitForUID(GetCompilandId(*pdb_data)).get();
+ // FIXME: We are not able to determine the compile unit.
+ if (sc.comp_unit == nullptr)
+ continue;
+
+ if (parent_decl_ctx.IsValid() &&
+ GetDeclContextContainingUID(result->getSymIndexId()) != parent_decl_ctx)
+ continue;
+
+ ParseVariables(sc, *pdb_data, &variables);
+ matches = variables.GetSize() - old_size;
+ }
+}
+
+void SymbolFilePDB::FindGlobalVariables(
+ const lldb_private::RegularExpression &regex, uint32_t max_matches,
+ lldb_private::VariableList &variables) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ if (!regex.IsValid())
+ return;
+ auto results = m_global_scope_up->findAllChildren<PDBSymbolData>();
+ if (!results)
+ return;
+
+ uint32_t matches = 0;
+ size_t old_size = variables.GetSize();
+ while (auto pdb_data = results->getNext()) {
+ if (max_matches > 0 && matches >= max_matches)
+ break;
+
+ auto var_name = pdb_data->getName();
+ if (var_name.empty())
+ continue;
+ if (!regex.Execute(var_name))
+ continue;
+ SymbolContext sc;
+ sc.module_sp = m_objfile_sp->GetModule();
+ lldbassert(sc.module_sp.get());
+
+ sc.comp_unit = ParseCompileUnitForUID(GetCompilandId(*pdb_data)).get();
+ // FIXME: We are not able to determine the compile unit.
+ if (sc.comp_unit == nullptr)
+ continue;
+
+ ParseVariables(sc, *pdb_data, &variables);
+ matches = variables.GetSize() - old_size;
+ }
+}
+
+bool SymbolFilePDB::ResolveFunction(const llvm::pdb::PDBSymbolFunc &pdb_func,
+ bool include_inlines,
+ lldb_private::SymbolContextList &sc_list) {
+ lldb_private::SymbolContext sc;
+ sc.comp_unit = ParseCompileUnitForUID(pdb_func.getCompilandId()).get();
+ if (!sc.comp_unit)
+ return false;
+ sc.module_sp = sc.comp_unit->GetModule();
+ sc.function = ParseCompileUnitFunctionForPDBFunc(pdb_func, *sc.comp_unit);
+ if (!sc.function)
+ return false;
+
+ sc_list.Append(sc);
+ return true;
+}
+
+bool SymbolFilePDB::ResolveFunction(uint32_t uid, bool include_inlines,
+ lldb_private::SymbolContextList &sc_list) {
+ auto pdb_func_up = m_session_up->getConcreteSymbolById<PDBSymbolFunc>(uid);
+ if (!pdb_func_up && !(include_inlines && pdb_func_up->hasInlineAttribute()))
+ return false;
+ return ResolveFunction(*pdb_func_up, include_inlines, sc_list);
+}
+
+void SymbolFilePDB::CacheFunctionNames() {
+ if (!m_func_full_names.IsEmpty())
+ return;
+
+ std::map<uint64_t, uint32_t> addr_ids;
+
+ if (auto results_up = m_global_scope_up->findAllChildren<PDBSymbolFunc>()) {
+ while (auto pdb_func_up = results_up->getNext()) {
+ if (pdb_func_up->isCompilerGenerated())
+ continue;
+
+ auto name = pdb_func_up->getName();
+ auto demangled_name = pdb_func_up->getUndecoratedName();
+ if (name.empty() && demangled_name.empty())
+ continue;
+
+ auto uid = pdb_func_up->getSymIndexId();
+ if (!demangled_name.empty() && pdb_func_up->getVirtualAddress())
+ addr_ids.insert(std::make_pair(pdb_func_up->getVirtualAddress(), uid));
+
+ if (auto parent = pdb_func_up->getClassParent()) {
+
+ // PDB have symbols for class/struct methods or static methods in Enum
+ // Class. We won't bother to check if the parent is UDT or Enum here.
+ m_func_method_names.Append(ConstString(name), uid);
+
+ // To search a method name, like NS::Class:MemberFunc, LLDB searches
+ // its base name, i.e. MemberFunc by default. Since PDBSymbolFunc does
+ // not have information of this, we extract base names and cache them
+ // by our own effort.
+ llvm::StringRef basename = MSVCUndecoratedNameParser::DropScope(name);
+ if (!basename.empty())
+ m_func_base_names.Append(ConstString(basename), uid);
+ else {
+ m_func_base_names.Append(ConstString(name), uid);
+ }
+
+ if (!demangled_name.empty())
+ m_func_full_names.Append(ConstString(demangled_name), uid);
+
+ } else {
+ // Handle not-method symbols.
+
+ // The function name might contain namespace, or its lexical scope.
+ llvm::StringRef basename = MSVCUndecoratedNameParser::DropScope(name);
+ if (!basename.empty())
+ m_func_base_names.Append(ConstString(basename), uid);
+ else
+ m_func_base_names.Append(ConstString(name), uid);
+
+ if (name == "main") {
+ m_func_full_names.Append(ConstString(name), uid);
+
+ if (!demangled_name.empty() && name != demangled_name) {
+ m_func_full_names.Append(ConstString(demangled_name), uid);
+ m_func_base_names.Append(ConstString(demangled_name), uid);
+ }
+ } else if (!demangled_name.empty()) {
+ m_func_full_names.Append(ConstString(demangled_name), uid);
+ } else {
+ m_func_full_names.Append(ConstString(name), uid);
+ }
+ }
+ }
+ }
+
+ if (auto results_up =
+ m_global_scope_up->findAllChildren<PDBSymbolPublicSymbol>()) {
+ while (auto pub_sym_up = results_up->getNext()) {
+ if (!pub_sym_up->isFunction())
+ continue;
+ auto name = pub_sym_up->getName();
+ if (name.empty())
+ continue;
+
+ if (CPlusPlusLanguage::IsCPPMangledName(name.c_str())) {
+ auto vm_addr = pub_sym_up->getVirtualAddress();
+
+ // PDB public symbol has mangled name for its associated function.
+ if (vm_addr && addr_ids.find(vm_addr) != addr_ids.end()) {
+ // Cache mangled name.
+ m_func_full_names.Append(ConstString(name), addr_ids[vm_addr]);
+ }
+ }
+ }
+ }
+ // Sort them before value searching is working properly
+ m_func_full_names.Sort();
+ m_func_full_names.SizeToFit();
+ m_func_method_names.Sort();
+ m_func_method_names.SizeToFit();
+ m_func_base_names.Sort();
+ m_func_base_names.SizeToFit();
+}
+
+void SymbolFilePDB::FindFunctions(
+ const lldb_private::Module::LookupInfo &lookup_info,
+ const lldb_private::CompilerDeclContext &parent_decl_ctx,
+ bool include_inlines,
+ lldb_private::SymbolContextList &sc_list) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ ConstString name = lookup_info.GetLookupName();
+ FunctionNameType name_type_mask = lookup_info.GetNameTypeMask();
+ lldbassert((name_type_mask & eFunctionNameTypeAuto) == 0);
+
+ if (name_type_mask & eFunctionNameTypeFull)
+ name = lookup_info.GetName();
+
+ if (name_type_mask == eFunctionNameTypeNone)
+ return;
+ if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx))
+ return;
+ if (name.IsEmpty())
+ return;
+
+ if (name_type_mask & eFunctionNameTypeFull ||
+ name_type_mask & eFunctionNameTypeBase ||
+ name_type_mask & eFunctionNameTypeMethod) {
+ CacheFunctionNames();
+
+ std::set<uint32_t> resolved_ids;
+ auto ResolveFn = [this, &name, parent_decl_ctx, include_inlines, &sc_list,
+ &resolved_ids](UniqueCStringMap<uint32_t> &Names) {
+ std::vector<uint32_t> ids;
+ if (!Names.GetValues(name, ids))
+ return;
+
+ for (uint32_t id : ids) {
+ if (resolved_ids.find(id) != resolved_ids.end())
+ continue;
+
+ if (parent_decl_ctx.IsValid() &&
+ GetDeclContextContainingUID(id) != parent_decl_ctx)
+ continue;
+
+ if (ResolveFunction(id, include_inlines, sc_list))
+ resolved_ids.insert(id);
+ }
+ };
+ if (name_type_mask & eFunctionNameTypeFull) {
+ ResolveFn(m_func_full_names);
+ ResolveFn(m_func_base_names);
+ ResolveFn(m_func_method_names);
+ }
+ if (name_type_mask & eFunctionNameTypeBase)
+ ResolveFn(m_func_base_names);
+ if (name_type_mask & eFunctionNameTypeMethod)
+ ResolveFn(m_func_method_names);
+ }
+}
+
+void SymbolFilePDB::FindFunctions(const lldb_private::RegularExpression &regex,
+ bool include_inlines,
+ lldb_private::SymbolContextList &sc_list) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ if (!regex.IsValid())
+ return;
+
+ CacheFunctionNames();
+
+ std::set<uint32_t> resolved_ids;
+ auto ResolveFn = [&regex, include_inlines, &sc_list, &resolved_ids,
+ this](UniqueCStringMap<uint32_t> &Names) {
+ std::vector<uint32_t> ids;
+ if (Names.GetValues(regex, ids)) {
+ for (auto id : ids) {
+ if (resolved_ids.find(id) == resolved_ids.end())
+ if (ResolveFunction(id, include_inlines, sc_list))
+ resolved_ids.insert(id);
+ }
+ }
+ };
+ ResolveFn(m_func_full_names);
+ ResolveFn(m_func_base_names);
+}
+
+void SymbolFilePDB::GetMangledNamesForFunction(
+ const std::string &scope_qualified_name,
+ std::vector<lldb_private::ConstString> &mangled_names) {}
+
+void SymbolFilePDB::AddSymbols(lldb_private::Symtab &symtab) {
+ std::set<lldb::addr_t> sym_addresses;
+ for (size_t i = 0; i < symtab.GetNumSymbols(); i++)
+ sym_addresses.insert(symtab.SymbolAtIndex(i)->GetFileAddress());
+
+ auto results = m_global_scope_up->findAllChildren<PDBSymbolPublicSymbol>();
+ if (!results)
+ return;
+
+ auto section_list = m_objfile_sp->GetSectionList();
+ if (!section_list)
+ return;
+
+ while (auto pub_symbol = results->getNext()) {
+ auto section_id = pub_symbol->getAddressSection();
+
+ auto section = section_list->FindSectionByID(section_id);
+ if (!section)
+ continue;
+
+ auto offset = pub_symbol->getAddressOffset();
+
+ auto file_addr = section->GetFileAddress() + offset;
+ if (sym_addresses.find(file_addr) != sym_addresses.end())
+ continue;
+ sym_addresses.insert(file_addr);
+
+ auto size = pub_symbol->getLength();
+ symtab.AddSymbol(
+ Symbol(pub_symbol->getSymIndexId(), // symID
+ pub_symbol->getName().c_str(), // name
+ pub_symbol->isCode() ? eSymbolTypeCode : eSymbolTypeData, // type
+ true, // external
+ false, // is_debug
+ false, // is_trampoline
+ false, // is_artificial
+ section, // section_sp
+ offset, // value
+ size, // size
+ size != 0, // size_is_valid
+ false, // contains_linker_annotations
+ 0 // flags
+ ));
+ }
+
+ symtab.Finalize();
+}
+
+void SymbolFilePDB::DumpClangAST(Stream &s) {
+ auto type_system_or_err =
+ GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
+ if (auto err = type_system_or_err.takeError()) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Symbols), std::move(err),
+ "Unable to dump ClangAST: {0}");
+ return;
+ }
+
+ auto ts = *type_system_or_err;
+ TypeSystemClang *clang_type_system =
+ llvm::dyn_cast_or_null<TypeSystemClang>(ts.get());
+ if (!clang_type_system)
+ return;
+ clang_type_system->Dump(s.AsRawOstream());
+}
+
+void SymbolFilePDB::FindTypesByRegex(
+ const lldb_private::RegularExpression &regex, uint32_t max_matches,
+ lldb_private::TypeMap &types) {
+ // When searching by regex, we need to go out of our way to limit the search
+ // space as much as possible since this searches EVERYTHING in the PDB,
+ // manually doing regex comparisons. PDB library isn't optimized for regex
+ // searches or searches across multiple symbol types at the same time, so the
+ // best we can do is to search enums, then typedefs, then classes one by one,
+ // and do a regex comparison against each of them.
+ PDB_SymType tags_to_search[] = {PDB_SymType::Enum, PDB_SymType::Typedef,
+ PDB_SymType::UDT};
+ std::unique_ptr<IPDBEnumSymbols> results;
+
+ uint32_t matches = 0;
+
+ for (auto tag : tags_to_search) {
+ results = m_global_scope_up->findAllChildren(tag);
+ if (!results)
+ continue;
+
+ while (auto result = results->getNext()) {
+ if (max_matches > 0 && matches >= max_matches)
+ break;
+
+ std::string type_name;
+ if (auto enum_type = llvm::dyn_cast<PDBSymbolTypeEnum>(result.get()))
+ type_name = enum_type->getName();
+ else if (auto typedef_type =
+ llvm::dyn_cast<PDBSymbolTypeTypedef>(result.get()))
+ type_name = typedef_type->getName();
+ else if (auto class_type = llvm::dyn_cast<PDBSymbolTypeUDT>(result.get()))
+ type_name = class_type->getName();
+ else {
+ // We're looking only for types that have names. Skip symbols, as well
+ // as unnamed types such as arrays, pointers, etc.
+ continue;
+ }
+
+ if (!regex.Execute(type_name))
+ continue;
+
+ // This should cause the type to get cached and stored in the `m_types`
+ // lookup.
+ if (!ResolveTypeUID(result->getSymIndexId()))
+ continue;
+
+ auto iter = m_types.find(result->getSymIndexId());
+ if (iter == m_types.end())
+ continue;
+ types.Insert(iter->second);
+ ++matches;
+ }
+ }
+}
+
+void SymbolFilePDB::FindTypes(const lldb_private::TypeQuery &query,
+ lldb_private::TypeResults &type_results) {
+
+ // Make sure we haven't already searched this SymbolFile before.
+ if (type_results.AlreadySearched(this))
+ return;
+
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+
+ std::unique_ptr<IPDBEnumSymbols> results;
+ llvm::StringRef basename = query.GetTypeBasename().GetStringRef();
+ if (basename.empty())
+ return;
+ results = m_global_scope_up->findAllChildren(PDB_SymType::None);
+ if (!results)
+ return;
+
+ while (auto result = results->getNext()) {
+
+ switch (result->getSymTag()) {
+ case PDB_SymType::Enum:
+ case PDB_SymType::UDT:
+ case PDB_SymType::Typedef:
+ break;
+ default:
+ // We're looking only for types that have names. Skip symbols, as well
+ // as unnamed types such as arrays, pointers, etc.
+ continue;
+ }
+
+ if (MSVCUndecoratedNameParser::DropScope(
+ result->getRawSymbol().getName()) != basename)
+ continue;
+
+ // This should cause the type to get cached and stored in the `m_types`
+ // lookup.
+ if (!ResolveTypeUID(result->getSymIndexId()))
+ continue;
+
+ auto iter = m_types.find(result->getSymIndexId());
+ if (iter == m_types.end())
+ continue;
+ // We resolved a type. Get the fully qualified name to ensure it matches.
+ ConstString name = iter->second->GetQualifiedName();
+ TypeQuery type_match(name.GetStringRef(), TypeQueryOptions::e_exact_match);
+ if (query.ContextMatches(type_match.GetContextRef())) {
+ type_results.InsertUnique(iter->second);
+ if (type_results.Done(query))
+ return;
+ }
+ }
+}
+
+void SymbolFilePDB::GetTypesForPDBSymbol(const llvm::pdb::PDBSymbol &pdb_symbol,
+ uint32_t type_mask,
+ TypeCollection &type_collection) {
+ bool can_parse = false;
+ switch (pdb_symbol.getSymTag()) {
+ case PDB_SymType::ArrayType:
+ can_parse = ((type_mask & eTypeClassArray) != 0);
+ break;
+ case PDB_SymType::BuiltinType:
+ can_parse = ((type_mask & eTypeClassBuiltin) != 0);
+ break;
+ case PDB_SymType::Enum:
+ can_parse = ((type_mask & eTypeClassEnumeration) != 0);
+ break;
+ case PDB_SymType::Function:
+ case PDB_SymType::FunctionSig:
+ can_parse = ((type_mask & eTypeClassFunction) != 0);
+ break;
+ case PDB_SymType::PointerType:
+ can_parse = ((type_mask & (eTypeClassPointer | eTypeClassBlockPointer |
+ eTypeClassMemberPointer)) != 0);
+ break;
+ case PDB_SymType::Typedef:
+ can_parse = ((type_mask & eTypeClassTypedef) != 0);
+ break;
+ case PDB_SymType::UDT: {
+ auto *udt = llvm::dyn_cast<PDBSymbolTypeUDT>(&pdb_symbol);
+ assert(udt);
+ can_parse = (udt->getUdtKind() != PDB_UdtType::Interface &&
+ ((type_mask & (eTypeClassClass | eTypeClassStruct |
+ eTypeClassUnion)) != 0));
+ } break;
+ default:
+ break;
+ }
+
+ if (can_parse) {
+ if (auto *type = ResolveTypeUID(pdb_symbol.getSymIndexId())) {
+ if (!llvm::is_contained(type_collection, type))
+ type_collection.push_back(type);
+ }
+ }
+
+ auto results_up = pdb_symbol.findAllChildren();
+ while (auto symbol_up = results_up->getNext())
+ GetTypesForPDBSymbol(*symbol_up, type_mask, type_collection);
+}
+
+void SymbolFilePDB::GetTypes(lldb_private::SymbolContextScope *sc_scope,
+ TypeClass type_mask,
+ lldb_private::TypeList &type_list) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ TypeCollection type_collection;
+ CompileUnit *cu =
+ sc_scope ? sc_scope->CalculateSymbolContextCompileUnit() : nullptr;
+ if (cu) {
+ auto compiland_up = GetPDBCompilandByUID(cu->GetID());
+ if (!compiland_up)
+ return;
+ GetTypesForPDBSymbol(*compiland_up, type_mask, type_collection);
+ } else {
+ for (uint32_t cu_idx = 0; cu_idx < GetNumCompileUnits(); ++cu_idx) {
+ auto cu_sp = ParseCompileUnitAtIndex(cu_idx);
+ if (cu_sp) {
+ if (auto compiland_up = GetPDBCompilandByUID(cu_sp->GetID()))
+ GetTypesForPDBSymbol(*compiland_up, type_mask, type_collection);
+ }
+ }
+ }
+
+ for (auto type : type_collection) {
+ type->GetForwardCompilerType();
+ type_list.Insert(type->shared_from_this());
+ }
+}
+
+llvm::Expected<lldb::TypeSystemSP>
+SymbolFilePDB::GetTypeSystemForLanguage(lldb::LanguageType 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;
+}
+
+PDBASTParser *SymbolFilePDB::GetPDBAstParser() {
+ auto type_system_or_err =
+ GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
+ if (auto err = type_system_or_err.takeError()) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Symbols), std::move(err),
+ "Unable to get PDB AST parser: {0}");
+ return nullptr;
+ }
+
+ auto ts = *type_system_or_err;
+ auto *clang_type_system =
+ llvm::dyn_cast_or_null<TypeSystemClang>(ts.get());
+ if (!clang_type_system)
+ return nullptr;
+
+ return clang_type_system->GetPDBParser();
+}
+
+lldb_private::CompilerDeclContext
+SymbolFilePDB::FindNamespace(lldb_private::ConstString name,
+ const CompilerDeclContext &parent_decl_ctx, bool) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ auto type_system_or_err =
+ GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
+ if (auto err = type_system_or_err.takeError()) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Symbols), std::move(err),
+ "Unable to find namespace {1}: {0}", name.AsCString());
+ return CompilerDeclContext();
+ }
+ auto ts = *type_system_or_err;
+ auto *clang_type_system =
+ llvm::dyn_cast_or_null<TypeSystemClang>(ts.get());
+ if (!clang_type_system)
+ return CompilerDeclContext();
+
+ PDBASTParser *pdb = clang_type_system->GetPDBParser();
+ if (!pdb)
+ return CompilerDeclContext();
+
+ clang::DeclContext *decl_context = nullptr;
+ if (parent_decl_ctx)
+ decl_context = static_cast<clang::DeclContext *>(
+ parent_decl_ctx.GetOpaqueDeclContext());
+
+ auto namespace_decl =
+ pdb->FindNamespaceDecl(decl_context, name.GetStringRef());
+ if (!namespace_decl)
+ return CompilerDeclContext();
+
+ return clang_type_system->CreateDeclContext(namespace_decl);
+}
+
+IPDBSession &SymbolFilePDB::GetPDBSession() { return *m_session_up; }
+
+const IPDBSession &SymbolFilePDB::GetPDBSession() const {
+ return *m_session_up;
+}
+
+lldb::CompUnitSP SymbolFilePDB::ParseCompileUnitForUID(uint32_t id,
+ uint32_t index) {
+ auto found_cu = m_comp_units.find(id);
+ if (found_cu != m_comp_units.end())
+ return found_cu->second;
+
+ auto compiland_up = GetPDBCompilandByUID(id);
+ if (!compiland_up)
+ return CompUnitSP();
+
+ lldb::LanguageType lang;
+ auto details = compiland_up->findOneChild<PDBSymbolCompilandDetails>();
+ if (!details)
+ lang = lldb::eLanguageTypeC_plus_plus;
+ else
+ lang = TranslateLanguage(details->getLanguage());
+
+ if (lang == lldb::LanguageType::eLanguageTypeUnknown)
+ return CompUnitSP();
+
+ std::string path = compiland_up->getSourceFileFullPath();
+ if (path.empty())
+ return CompUnitSP();
+
+ // Don't support optimized code for now, DebugInfoPDB does not return this
+ // information.
+ LazyBool optimized = eLazyBoolNo;
+ auto cu_sp = std::make_shared<CompileUnit>(m_objfile_sp->GetModule(), nullptr,
+ path.c_str(), id, lang, optimized);
+
+ if (!cu_sp)
+ return CompUnitSP();
+
+ m_comp_units.insert(std::make_pair(id, cu_sp));
+ if (index == UINT32_MAX)
+ GetCompileUnitIndex(*compiland_up, index);
+ lldbassert(index != UINT32_MAX);
+ SetCompileUnitAtIndex(index, cu_sp);
+ return cu_sp;
+}
+
+bool SymbolFilePDB::ParseCompileUnitLineTable(CompileUnit &comp_unit,
+ uint32_t match_line) {
+ auto compiland_up = GetPDBCompilandByUID(comp_unit.GetID());
+ if (!compiland_up)
+ return false;
+
+ // LineEntry needs the *index* of the file into the list of support files
+ // returned by ParseCompileUnitSupportFiles. But the underlying SDK gives us
+ // a globally unique idenfitifier in the namespace of the PDB. So, we have
+ // to do a mapping so that we can hand out indices.
+ llvm::DenseMap<uint32_t, uint32_t> index_map;
+ BuildSupportFileIdToSupportFileIndexMap(*compiland_up, index_map);
+ auto line_table = std::make_unique<LineTable>(&comp_unit);
+
+ // Find contributions to `compiland` from all source and header files.
+ auto files = m_session_up->getSourceFilesForCompiland(*compiland_up);
+ if (!files)
+ return false;
+
+ // For each source and header file, create a LineSequence for contributions
+ // to the compiland from that file, and add the sequence.
+ while (auto file = files->getNext()) {
+ std::unique_ptr<LineSequence> sequence(
+ line_table->CreateLineSequenceContainer());
+ auto lines = m_session_up->findLineNumbers(*compiland_up, *file);
+ if (!lines)
+ continue;
+ int entry_count = lines->getChildCount();
+
+ uint64_t prev_addr;
+ uint32_t prev_length;
+ uint32_t prev_line;
+ uint32_t prev_source_idx;
+
+ for (int i = 0; i < entry_count; ++i) {
+ auto line = lines->getChildAtIndex(i);
+
+ uint64_t lno = line->getLineNumber();
+ uint64_t addr = line->getVirtualAddress();
+ uint32_t length = line->getLength();
+ uint32_t source_id = line->getSourceFileId();
+ uint32_t col = line->getColumnNumber();
+ uint32_t source_idx = index_map[source_id];
+
+ // There was a gap between the current entry and the previous entry if
+ // the addresses don't perfectly line up.
+ bool is_gap = (i > 0) && (prev_addr + prev_length < addr);
+
+ // Before inserting the current entry, insert a terminal entry at the end
+ // of the previous entry's address range if the current entry resulted in
+ // a gap from the previous entry.
+ if (is_gap && ShouldAddLine(match_line, prev_line, prev_length)) {
+ line_table->AppendLineEntryToSequence(
+ sequence.get(), prev_addr + prev_length, prev_line, 0,
+ prev_source_idx, false, false, false, false, true);
+
+ line_table->InsertSequence(sequence.get());
+ sequence = line_table->CreateLineSequenceContainer();
+ }
+
+ if (ShouldAddLine(match_line, lno, length)) {
+ bool is_statement = line->isStatement();
+ bool is_prologue = false;
+ bool is_epilogue = false;
+ auto func =
+ m_session_up->findSymbolByAddress(addr, PDB_SymType::Function);
+ if (func) {
+ auto prologue = func->findOneChild<PDBSymbolFuncDebugStart>();
+ if (prologue)
+ is_prologue = (addr == prologue->getVirtualAddress());
+
+ auto epilogue = func->findOneChild<PDBSymbolFuncDebugEnd>();
+ if (epilogue)
+ is_epilogue = (addr == epilogue->getVirtualAddress());
+ }
+
+ line_table->AppendLineEntryToSequence(sequence.get(), addr, lno, col,
+ source_idx, is_statement, false,
+ is_prologue, is_epilogue, false);
+ }
+
+ prev_addr = addr;
+ prev_length = length;
+ prev_line = lno;
+ prev_source_idx = source_idx;
+ }
+
+ if (entry_count > 0 && ShouldAddLine(match_line, prev_line, prev_length)) {
+ // The end is always a terminal entry, so insert it regardless.
+ line_table->AppendLineEntryToSequence(
+ sequence.get(), prev_addr + prev_length, prev_line, 0,
+ prev_source_idx, false, false, false, false, true);
+ }
+
+ line_table->InsertSequence(sequence.get());
+ }
+
+ if (line_table->GetSize()) {
+ comp_unit.SetLineTable(line_table.release());
+ return true;
+ }
+ return false;
+}
+
+void SymbolFilePDB::BuildSupportFileIdToSupportFileIndexMap(
+ const PDBSymbolCompiland &compiland,
+ llvm::DenseMap<uint32_t, uint32_t> &index_map) const {
+ // This is a hack, but we need to convert the source id into an index into
+ // the support files array. We don't want to do path comparisons to avoid
+ // basename / full path issues that may or may not even be a problem, so we
+ // use the globally unique source file identifiers. Ideally we could use the
+ // global identifiers everywhere, but LineEntry currently assumes indices.
+ auto source_files = m_session_up->getSourceFilesForCompiland(compiland);
+ if (!source_files)
+ return;
+
+ int index = 0;
+ while (auto file = source_files->getNext()) {
+ uint32_t source_id = file->getUniqueId();
+ index_map[source_id] = index++;
+ }
+}
+
+lldb::CompUnitSP SymbolFilePDB::GetCompileUnitContainsAddress(
+ const lldb_private::Address &so_addr) {
+ lldb::addr_t file_vm_addr = so_addr.GetFileAddress();
+ if (file_vm_addr == LLDB_INVALID_ADDRESS || file_vm_addr == 0)
+ return nullptr;
+
+ // If it is a PDB function's vm addr, this is the first sure bet.
+ if (auto lines =
+ m_session_up->findLineNumbersByAddress(file_vm_addr, /*Length=*/1)) {
+ if (auto first_line = lines->getNext())
+ return ParseCompileUnitForUID(first_line->getCompilandId());
+ }
+
+ // Otherwise we resort to section contributions.
+ if (auto sec_contribs = m_session_up->getSectionContribs()) {
+ while (auto section = sec_contribs->getNext()) {
+ auto va = section->getVirtualAddress();
+ if (file_vm_addr >= va && file_vm_addr < va + section->getLength())
+ return ParseCompileUnitForUID(section->getCompilandId());
+ }
+ }
+ return nullptr;
+}
+
+Mangled
+SymbolFilePDB::GetMangledForPDBFunc(const llvm::pdb::PDBSymbolFunc &pdb_func) {
+ Mangled mangled;
+ auto func_name = pdb_func.getName();
+ auto func_undecorated_name = pdb_func.getUndecoratedName();
+ std::string func_decorated_name;
+
+ // Seek from public symbols for non-static function's decorated name if any.
+ // For static functions, they don't have undecorated names and aren't exposed
+ // in Public Symbols either.
+ if (!func_undecorated_name.empty()) {
+ auto result_up = m_global_scope_up->findChildren(
+ PDB_SymType::PublicSymbol, func_undecorated_name,
+ PDB_NameSearchFlags::NS_UndecoratedName);
+ if (result_up) {
+ while (auto symbol_up = result_up->getNext()) {
+ // For a public symbol, it is unique.
+ lldbassert(result_up->getChildCount() == 1);
+ if (auto *pdb_public_sym =
+ llvm::dyn_cast_or_null<PDBSymbolPublicSymbol>(
+ symbol_up.get())) {
+ if (pdb_public_sym->isFunction()) {
+ func_decorated_name = pdb_public_sym->getName();
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (!func_decorated_name.empty()) {
+ mangled.SetMangledName(ConstString(func_decorated_name));
+
+ // For MSVC, format of C function's decorated name depends on calling
+ // convention. Unfortunately none of the format is recognized by current
+ // LLDB. For example, `_purecall` is a __cdecl C function. From PDB,
+ // `__purecall` is retrieved as both its decorated and undecorated name
+ // (using PDBSymbolFunc::getUndecoratedName method). However `__purecall`
+ // string is not treated as mangled in LLDB (neither `?` nor `_Z` prefix).
+ // Mangled::GetDemangledName method will fail internally and caches an
+ // empty string as its undecorated name. So we will face a contradiction
+ // here for the same symbol:
+ // non-empty undecorated name from PDB
+ // empty undecorated name from LLDB
+ if (!func_undecorated_name.empty() && mangled.GetDemangledName().IsEmpty())
+ mangled.SetDemangledName(ConstString(func_undecorated_name));
+
+ // LLDB uses several flags to control how a C++ decorated name is
+ // undecorated for MSVC. See `safeUndecorateName` in Class Mangled. So the
+ // yielded name could be different from what we retrieve from
+ // PDB source unless we also apply same flags in getting undecorated
+ // name through PDBSymbolFunc::getUndecoratedNameEx method.
+ if (!func_undecorated_name.empty() &&
+ mangled.GetDemangledName() != ConstString(func_undecorated_name))
+ mangled.SetDemangledName(ConstString(func_undecorated_name));
+ } else if (!func_undecorated_name.empty()) {
+ mangled.SetDemangledName(ConstString(func_undecorated_name));
+ } else if (!func_name.empty())
+ mangled.SetValue(ConstString(func_name));
+
+ return mangled;
+}
+
+bool SymbolFilePDB::DeclContextMatchesThisSymbolFile(
+ const lldb_private::CompilerDeclContext &decl_ctx) {
+ if (!decl_ctx.IsValid())
+ return true;
+
+ TypeSystem *decl_ctx_type_system = decl_ctx.GetTypeSystem();
+ if (!decl_ctx_type_system)
+ return false;
+ 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 determine if DeclContext matches this symbol file: {0}");
+ return false;
+ }
+
+ if (decl_ctx_type_system == type_system_or_err->get())
+ return true; // The type systems match, return true
+
+ return false;
+}
+
+uint32_t SymbolFilePDB::GetCompilandId(const llvm::pdb::PDBSymbolData &data) {
+ static const auto pred_upper = [](uint32_t lhs, SecContribInfo rhs) {
+ return lhs < rhs.Offset;
+ };
+
+ // Cache section contributions
+ if (m_sec_contribs.empty()) {
+ if (auto SecContribs = m_session_up->getSectionContribs()) {
+ while (auto SectionContrib = SecContribs->getNext()) {
+ auto comp_id = SectionContrib->getCompilandId();
+ if (!comp_id)
+ continue;
+
+ auto sec = SectionContrib->getAddressSection();
+ auto &sec_cs = m_sec_contribs[sec];
+
+ auto offset = SectionContrib->getAddressOffset();
+ auto it = llvm::upper_bound(sec_cs, offset, pred_upper);
+
+ auto size = SectionContrib->getLength();
+ sec_cs.insert(it, {offset, size, comp_id});
+ }
+ }
+ }
+
+ // Check by line number
+ if (auto Lines = data.getLineNumbers()) {
+ if (auto FirstLine = Lines->getNext())
+ return FirstLine->getCompilandId();
+ }
+
+ // Retrieve section + offset
+ uint32_t DataSection = data.getAddressSection();
+ uint32_t DataOffset = data.getAddressOffset();
+ if (DataSection == 0) {
+ if (auto RVA = data.getRelativeVirtualAddress())
+ m_session_up->addressForRVA(RVA, DataSection, DataOffset);
+ }
+
+ if (DataSection) {
+ // Search by section contributions
+ auto &sec_cs = m_sec_contribs[DataSection];
+ auto it = llvm::upper_bound(sec_cs, DataOffset, pred_upper);
+ if (it != sec_cs.begin()) {
+ --it;
+ if (DataOffset < it->Offset + it->Size)
+ return it->CompilandId;
+ }
+ } else {
+ // Search in lexical tree
+ auto LexParentId = data.getLexicalParentId();
+ while (auto LexParent = m_session_up->getSymbolById(LexParentId)) {
+ if (LexParent->getSymTag() == PDB_SymType::Exe)
+ break;
+ if (LexParent->getSymTag() == PDB_SymType::Compiland)
+ return LexParentId;
+ LexParentId = LexParent->getRawSymbol().getLexicalParentId();
+ }
+ }
+
+ return 0;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h
new file mode 100644
index 000000000000..ea495c575f1f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h
@@ -0,0 +1,252 @@
+//===-- SymbolFilePDB.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_PDB_SYMBOLFILEPDB_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_PDB_SYMBOLFILEPDB_H
+
+#include "lldb/Core/UniqueCStringMap.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Utility/UserID.h"
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/DebugInfo/PDB/IPDBSession.h"
+#include "llvm/DebugInfo/PDB/PDB.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
+#include <optional>
+
+class PDBASTParser;
+
+class SymbolFilePDB : public lldb_private::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 void DebuggerInitialize(lldb_private::Debugger &debugger);
+
+ static llvm::StringRef GetPluginNameStatic() { return "pdb"; }
+
+ static llvm::StringRef GetPluginDescriptionStatic();
+
+ static lldb_private::SymbolFile *
+ CreateInstance(lldb::ObjectFileSP objfile_sp);
+
+ // Constructors and Destructors
+ SymbolFilePDB(lldb::ObjectFileSP objfile_sp);
+
+ ~SymbolFilePDB() override;
+
+ uint32_t CalculateAbilities() override;
+
+ void InitializeObject() override;
+
+ // Compile Unit function calls
+
+ lldb::LanguageType
+ ParseLanguage(lldb_private::CompileUnit &comp_unit) override;
+
+ size_t ParseFunctions(lldb_private::CompileUnit &comp_unit) override;
+
+ bool ParseLineTable(lldb_private::CompileUnit &comp_unit) override;
+
+ bool ParseDebugMacros(lldb_private::CompileUnit &comp_unit) override;
+
+ bool ParseSupportFiles(lldb_private::CompileUnit &comp_unit,
+ lldb_private::SupportFileList &support_files) override;
+
+ size_t ParseTypes(lldb_private::CompileUnit &comp_unit) override;
+
+ bool ParseImportedModules(
+ const lldb_private::SymbolContext &sc,
+ std::vector<lldb_private::SourceModule> &imported_modules) override;
+
+ size_t ParseBlocksRecursive(lldb_private::Function &func) override;
+
+ size_t
+ ParseVariablesForContext(const lldb_private::SymbolContext &sc) override;
+
+ lldb_private::Type *ResolveTypeUID(lldb::user_id_t type_uid) override;
+ std::optional<ArrayInfo> GetDynamicArrayInfoForUID(
+ lldb::user_id_t type_uid,
+ const lldb_private::ExecutionContext *exe_ctx) override;
+
+ bool CompleteType(lldb_private::CompilerType &compiler_type) override;
+
+ lldb_private::CompilerDecl GetDeclForUID(lldb::user_id_t uid) override;
+
+ lldb_private::CompilerDeclContext
+ GetDeclContextForUID(lldb::user_id_t uid) override;
+
+ lldb_private::CompilerDeclContext
+ GetDeclContextContainingUID(lldb::user_id_t uid) override;
+
+ void
+ ParseDeclsForContext(lldb_private::CompilerDeclContext decl_ctx) override;
+
+ uint32_t ResolveSymbolContext(const lldb_private::Address &so_addr,
+ lldb::SymbolContextItem resolve_scope,
+ lldb_private::SymbolContext &sc) override;
+
+ uint32_t ResolveSymbolContext(
+ const lldb_private::SourceLocationSpec &src_location_spec,
+ lldb::SymbolContextItem resolve_scope,
+ lldb_private::SymbolContextList &sc_list) override;
+
+ void
+ FindGlobalVariables(lldb_private::ConstString name,
+ const lldb_private::CompilerDeclContext &parent_decl_ctx,
+ uint32_t max_matches,
+ lldb_private::VariableList &variables) override;
+
+ void FindGlobalVariables(const lldb_private::RegularExpression &regex,
+ uint32_t max_matches,
+ lldb_private::VariableList &variables) override;
+
+ void FindFunctions(const lldb_private::Module::LookupInfo &lookup_info,
+ const lldb_private::CompilerDeclContext &parent_decl_ctx,
+ bool include_inlines,
+ lldb_private::SymbolContextList &sc_list) override;
+
+ void FindFunctions(const lldb_private::RegularExpression &regex,
+ bool include_inlines,
+ lldb_private::SymbolContextList &sc_list) override;
+
+ void GetMangledNamesForFunction(
+ const std::string &scope_qualified_name,
+ std::vector<lldb_private::ConstString> &mangled_names) override;
+
+ void AddSymbols(lldb_private::Symtab &symtab) override;
+ void FindTypes(const lldb_private::TypeQuery &match,
+ lldb_private::TypeResults &results) override;
+ void FindTypesByRegex(const lldb_private::RegularExpression &regex,
+ uint32_t max_matches, lldb_private::TypeMap &types);
+
+ void GetTypes(lldb_private::SymbolContextScope *sc_scope,
+ lldb::TypeClass type_mask,
+ lldb_private::TypeList &type_list) override;
+
+ llvm::Expected<lldb::TypeSystemSP>
+ GetTypeSystemForLanguage(lldb::LanguageType language) override;
+
+ lldb_private::CompilerDeclContext
+ FindNamespace(lldb_private::ConstString name,
+ const lldb_private::CompilerDeclContext &parent_decl_ctx,
+ bool only_root_namespaces) override;
+
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+ llvm::pdb::IPDBSession &GetPDBSession();
+
+ const llvm::pdb::IPDBSession &GetPDBSession() const;
+
+ void DumpClangAST(lldb_private::Stream &s) override;
+
+private:
+ struct SecContribInfo {
+ uint32_t Offset;
+ uint32_t Size;
+ uint32_t CompilandId;
+ };
+ using SecContribsMap = std::map<uint32_t, std::vector<SecContribInfo>>;
+
+ uint32_t CalculateNumCompileUnits() override;
+
+ lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index) override;
+
+ lldb::CompUnitSP ParseCompileUnitForUID(uint32_t id,
+ uint32_t index = UINT32_MAX);
+
+ bool ParseCompileUnitLineTable(lldb_private::CompileUnit &comp_unit,
+ uint32_t match_line);
+
+ void BuildSupportFileIdToSupportFileIndexMap(
+ const llvm::pdb::PDBSymbolCompiland &pdb_compiland,
+ llvm::DenseMap<uint32_t, uint32_t> &index_map) const;
+
+ void FindTypesByName(llvm::StringRef name,
+ const lldb_private::CompilerDeclContext &parent_decl_ctx,
+ uint32_t max_matches, lldb_private::TypeMap &types);
+
+ std::string GetMangledForPDBData(const llvm::pdb::PDBSymbolData &pdb_data);
+
+ lldb::VariableSP
+ ParseVariableForPDBData(const lldb_private::SymbolContext &sc,
+ const llvm::pdb::PDBSymbolData &pdb_data);
+
+ size_t ParseVariables(const lldb_private::SymbolContext &sc,
+ const llvm::pdb::PDBSymbol &pdb_data,
+ lldb_private::VariableList *variable_list = nullptr);
+
+ lldb::CompUnitSP
+ GetCompileUnitContainsAddress(const lldb_private::Address &so_addr);
+
+ typedef std::vector<lldb_private::Type *> TypeCollection;
+
+ void GetTypesForPDBSymbol(const llvm::pdb::PDBSymbol &pdb_symbol,
+ uint32_t type_mask,
+ TypeCollection &type_collection);
+
+ lldb_private::Function *
+ ParseCompileUnitFunctionForPDBFunc(const llvm::pdb::PDBSymbolFunc &pdb_func,
+ lldb_private::CompileUnit &comp_unit);
+
+ void GetCompileUnitIndex(const llvm::pdb::PDBSymbolCompiland &pdb_compiland,
+ uint32_t &index);
+
+ PDBASTParser *GetPDBAstParser();
+
+ std::unique_ptr<llvm::pdb::PDBSymbolCompiland>
+ GetPDBCompilandByUID(uint32_t uid);
+
+ lldb_private::Mangled
+ GetMangledForPDBFunc(const llvm::pdb::PDBSymbolFunc &pdb_func);
+
+ bool ResolveFunction(const llvm::pdb::PDBSymbolFunc &pdb_func,
+ bool include_inlines,
+ lldb_private::SymbolContextList &sc_list);
+
+ bool ResolveFunction(uint32_t uid, bool include_inlines,
+ lldb_private::SymbolContextList &sc_list);
+
+ void CacheFunctionNames();
+
+ bool DeclContextMatchesThisSymbolFile(
+ const lldb_private::CompilerDeclContext &decl_ctx);
+
+ uint32_t GetCompilandId(const llvm::pdb::PDBSymbolData &data);
+
+ llvm::DenseMap<uint32_t, lldb::CompUnitSP> m_comp_units;
+ llvm::DenseMap<uint32_t, lldb::TypeSP> m_types;
+ llvm::DenseMap<uint32_t, lldb::VariableSP> m_variables;
+ llvm::DenseMap<uint64_t, std::string> m_public_names;
+
+ SecContribsMap m_sec_contribs;
+
+ std::vector<lldb::TypeSP> m_builtin_types;
+ std::unique_ptr<llvm::pdb::IPDBSession> m_session_up;
+ std::unique_ptr<llvm::pdb::PDBSymbolExe> m_global_scope_up;
+
+ lldb_private::UniqueCStringMap<uint32_t> m_func_full_names;
+ lldb_private::UniqueCStringMap<uint32_t> m_func_base_names;
+ lldb_private::UniqueCStringMap<uint32_t> m_func_method_names;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_PDB_SYMBOLFILEPDB_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp
new file mode 100644
index 000000000000..8c17017442b1
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp
@@ -0,0 +1,258 @@
+//===-- SymbolFileSymtab.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 "SymbolFileSymtab.h"
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Symtab.h"
+#include "lldb/Symbol/TypeList.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/Timer.h"
+
+#include <memory>
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+
+LLDB_PLUGIN_DEFINE(SymbolFileSymtab)
+
+char SymbolFileSymtab::ID;
+
+void SymbolFileSymtab::Initialize() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(), CreateInstance);
+}
+
+void SymbolFileSymtab::Terminate() {
+ PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+llvm::StringRef SymbolFileSymtab::GetPluginDescriptionStatic() {
+ return "Reads debug symbols from an object file's symbol table.";
+}
+
+SymbolFile *SymbolFileSymtab::CreateInstance(ObjectFileSP objfile_sp) {
+ return new SymbolFileSymtab(std::move(objfile_sp));
+}
+
+void SymbolFileSymtab::GetTypes(SymbolContextScope *sc_scope,
+ TypeClass type_mask,
+ lldb_private::TypeList &type_list) {}
+
+SymbolFileSymtab::SymbolFileSymtab(ObjectFileSP objfile_sp)
+ : SymbolFileCommon(std::move(objfile_sp)), m_source_indexes(),
+ m_func_indexes(), m_code_indexes(), m_objc_class_name_to_index() {}
+
+uint32_t SymbolFileSymtab::CalculateAbilities() {
+ uint32_t abilities = 0;
+ if (m_objfile_sp) {
+ const Symtab *symtab = m_objfile_sp->GetSymtab();
+ if (symtab) {
+ // The snippet of code below will get the indexes the module symbol table
+ // entries that are code, data, or function related (debug info), sort
+ // them by value (address) and dump the sorted symbols.
+ if (symtab->AppendSymbolIndexesWithType(eSymbolTypeSourceFile,
+ m_source_indexes)) {
+ abilities |= CompileUnits;
+ }
+
+ if (symtab->AppendSymbolIndexesWithType(
+ eSymbolTypeCode, Symtab::eDebugYes, Symtab::eVisibilityAny,
+ m_func_indexes)) {
+ symtab->SortSymbolIndexesByValue(m_func_indexes, true);
+ abilities |= Functions;
+ }
+
+ if (symtab->AppendSymbolIndexesWithType(eSymbolTypeCode, Symtab::eDebugNo,
+ Symtab::eVisibilityAny,
+ m_code_indexes)) {
+ symtab->SortSymbolIndexesByValue(m_code_indexes, true);
+ abilities |= Functions;
+ }
+
+ if (symtab->AppendSymbolIndexesWithType(eSymbolTypeData,
+ m_data_indexes)) {
+ symtab->SortSymbolIndexesByValue(m_data_indexes, true);
+ abilities |= GlobalVariables;
+ }
+
+ lldb_private::Symtab::IndexCollection objc_class_indexes;
+ if (symtab->AppendSymbolIndexesWithType(eSymbolTypeObjCClass,
+ objc_class_indexes)) {
+ symtab->AppendSymbolNamesToMap(objc_class_indexes, true, true,
+ m_objc_class_name_to_index);
+ m_objc_class_name_to_index.Sort();
+ }
+ }
+ }
+ return abilities;
+}
+
+uint32_t SymbolFileSymtab::CalculateNumCompileUnits() {
+ // If we don't have any source file symbols we will just have one compile
+ // unit for the entire object file
+ if (m_source_indexes.empty())
+ return 0;
+
+ // If we have any source file symbols we will logically organize the object
+ // symbols using these.
+ return m_source_indexes.size();
+}
+
+CompUnitSP SymbolFileSymtab::ParseCompileUnitAtIndex(uint32_t idx) {
+ CompUnitSP cu_sp;
+
+ // If we don't have any source file symbols we will just have one compile
+ // unit for the entire object file
+ if (idx < m_source_indexes.size()) {
+ const Symbol *cu_symbol =
+ m_objfile_sp->GetSymtab()->SymbolAtIndex(m_source_indexes[idx]);
+ if (cu_symbol)
+ cu_sp = std::make_shared<CompileUnit>(m_objfile_sp->GetModule(), nullptr,
+ cu_symbol->GetName().AsCString(), 0,
+ eLanguageTypeUnknown, eLazyBoolNo);
+ }
+ return cu_sp;
+}
+
+lldb::LanguageType SymbolFileSymtab::ParseLanguage(CompileUnit &comp_unit) {
+ return eLanguageTypeUnknown;
+}
+
+size_t SymbolFileSymtab::ParseFunctions(CompileUnit &comp_unit) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ size_t num_added = 0;
+ // We must at least have a valid compile unit
+ const Symtab *symtab = m_objfile_sp->GetSymtab();
+ const Symbol *curr_symbol = nullptr;
+ const Symbol *next_symbol = nullptr;
+ // const char *prefix = m_objfile_sp->SymbolPrefix();
+ // if (prefix == NULL)
+ // prefix == "";
+ //
+ // const uint32_t prefix_len = strlen(prefix);
+
+ // If we don't have any source file symbols we will just have one compile
+ // unit for the entire object file
+ if (m_source_indexes.empty()) {
+ // The only time we will have a user ID of zero is when we don't have and
+ // source file symbols and we declare one compile unit for the entire
+ // object file
+ if (!m_func_indexes.empty()) {
+ }
+
+ if (!m_code_indexes.empty()) {
+ // StreamFile s(stdout);
+ // symtab->Dump(&s, m_code_indexes);
+
+ uint32_t idx = 0; // Index into the indexes
+ const uint32_t num_indexes = m_code_indexes.size();
+ for (idx = 0; idx < num_indexes; ++idx) {
+ uint32_t symbol_idx = m_code_indexes[idx];
+ curr_symbol = symtab->SymbolAtIndex(symbol_idx);
+ if (curr_symbol) {
+ // Union of all ranges in the function DIE (if the function is
+ // discontiguous)
+ AddressRange func_range(curr_symbol->GetAddress(), 0);
+ if (func_range.GetBaseAddress().IsSectionOffset()) {
+ uint32_t symbol_size = curr_symbol->GetByteSize();
+ if (symbol_size != 0 && !curr_symbol->GetSizeIsSibling())
+ func_range.SetByteSize(symbol_size);
+ else if (idx + 1 < num_indexes) {
+ next_symbol = symtab->SymbolAtIndex(m_code_indexes[idx + 1]);
+ if (next_symbol) {
+ func_range.SetByteSize(
+ next_symbol->GetAddressRef().GetOffset() -
+ curr_symbol->GetAddressRef().GetOffset());
+ }
+ }
+
+ FunctionSP func_sp(
+ new Function(&comp_unit,
+ symbol_idx, // UserID is the DIE offset
+ LLDB_INVALID_UID, // We don't have any type info
+ // for this function
+ curr_symbol->GetMangled(), // Linker/mangled name
+ nullptr, // no return type for a code symbol...
+ func_range)); // first address range
+
+ if (func_sp.get() != nullptr) {
+ comp_unit.AddFunction(func_sp);
+ ++num_added;
+ }
+ }
+ }
+ }
+ }
+ } else {
+ // We assume we
+ }
+ return num_added;
+}
+
+size_t SymbolFileSymtab::ParseTypes(CompileUnit &comp_unit) { return 0; }
+
+bool SymbolFileSymtab::ParseLineTable(CompileUnit &comp_unit) { return false; }
+
+bool SymbolFileSymtab::ParseDebugMacros(CompileUnit &comp_unit) {
+ return false;
+}
+
+bool SymbolFileSymtab::ParseSupportFiles(CompileUnit &comp_unit,
+ SupportFileList &support_files) {
+ return false;
+}
+
+bool SymbolFileSymtab::ParseImportedModules(
+ const SymbolContext &sc, std::vector<SourceModule> &imported_modules) {
+ return false;
+}
+
+size_t SymbolFileSymtab::ParseBlocksRecursive(Function &func) { return 0; }
+
+size_t SymbolFileSymtab::ParseVariablesForContext(const SymbolContext &sc) {
+ return 0;
+}
+
+Type *SymbolFileSymtab::ResolveTypeUID(lldb::user_id_t type_uid) {
+ return nullptr;
+}
+
+std::optional<SymbolFile::ArrayInfo>
+SymbolFileSymtab::GetDynamicArrayInfoForUID(
+ lldb::user_id_t type_uid, const lldb_private::ExecutionContext *exe_ctx) {
+ return std::nullopt;
+}
+
+bool SymbolFileSymtab::CompleteType(lldb_private::CompilerType &compiler_type) {
+ return false;
+}
+
+uint32_t SymbolFileSymtab::ResolveSymbolContext(const Address &so_addr,
+ SymbolContextItem resolve_scope,
+ SymbolContext &sc) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ if (m_objfile_sp->GetSymtab() == nullptr)
+ return 0;
+
+ uint32_t resolved_flags = 0;
+ if (resolve_scope & eSymbolContextSymbol) {
+ sc.symbol = m_objfile_sp->GetSymtab()->FindSymbolContainingFileAddress(
+ so_addr.GetFileAddress());
+ if (sc.symbol)
+ resolved_flags |= eSymbolContextSymbol;
+ }
+ return resolved_flags;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h
new file mode 100644
index 000000000000..a36311525334
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h
@@ -0,0 +1,103 @@
+//===-- SymbolFileSymtab.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_SYMTAB_SYMBOLFILESYMTAB_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_SYMTAB_SYMBOLFILESYMTAB_H
+
+#include <map>
+#include <optional>
+#include <vector>
+
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Symbol/Symtab.h"
+
+class SymbolFileSymtab : public lldb_private::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); }
+ /// \}
+
+ // Constructors and Destructors
+ SymbolFileSymtab(lldb::ObjectFileSP objfile_sp);
+
+ // Static Functions
+ static void Initialize();
+
+ static void Terminate();
+
+ static llvm::StringRef GetPluginNameStatic() { return "symtab"; }
+
+ static llvm::StringRef GetPluginDescriptionStatic();
+
+ static lldb_private::SymbolFile *
+ CreateInstance(lldb::ObjectFileSP objfile_sp);
+
+ uint32_t CalculateAbilities() override;
+
+ // Compile Unit function calls
+ lldb::LanguageType
+ ParseLanguage(lldb_private::CompileUnit &comp_unit) override;
+
+ size_t ParseFunctions(lldb_private::CompileUnit &comp_unit) override;
+
+ bool ParseLineTable(lldb_private::CompileUnit &comp_unit) override;
+
+ bool ParseDebugMacros(lldb_private::CompileUnit &comp_unit) override;
+
+ bool ParseSupportFiles(lldb_private::CompileUnit &comp_unit,
+ lldb_private::SupportFileList &support_files) override;
+
+ size_t ParseTypes(lldb_private::CompileUnit &comp_unit) override;
+
+ bool ParseImportedModules(
+ const lldb_private::SymbolContext &sc,
+ std::vector<lldb_private::SourceModule> &imported_modules) override;
+
+ size_t ParseBlocksRecursive(lldb_private::Function &func) override;
+
+ size_t
+ ParseVariablesForContext(const lldb_private::SymbolContext &sc) override;
+
+ lldb_private::Type *ResolveTypeUID(lldb::user_id_t type_uid) override;
+ std::optional<ArrayInfo> GetDynamicArrayInfoForUID(
+ lldb::user_id_t type_uid,
+ const lldb_private::ExecutionContext *exe_ctx) override;
+
+ bool CompleteType(lldb_private::CompilerType &compiler_type) override;
+
+ uint32_t ResolveSymbolContext(const lldb_private::Address &so_addr,
+ lldb::SymbolContextItem resolve_scope,
+ lldb_private::SymbolContext &sc) override;
+
+ void GetTypes(lldb_private::SymbolContextScope *sc_scope,
+ lldb::TypeClass type_mask,
+ lldb_private::TypeList &type_list) override;
+
+ // PluginInterface protocol
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+protected:
+ uint32_t CalculateNumCompileUnits() override;
+
+ lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index) override;
+
+ lldb_private::Symtab::IndexCollection m_source_indexes;
+ lldb_private::Symtab::IndexCollection m_func_indexes;
+ lldb_private::Symtab::IndexCollection m_code_indexes;
+ lldb_private::Symtab::IndexCollection m_data_indexes;
+ lldb_private::Symtab::NameToIndexMap m_objc_class_name_to_index;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_SYMTAB_SYMBOLFILESYMTAB_H