aboutsummaryrefslogtreecommitdiffstats
path: root/source/Plugins/SymbolFile/NativePDB
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-01-19 10:06:29 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-01-19 10:06:29 +0000
commit94994d372d014ce4c8758b9605d63fae651bd8aa (patch)
tree51c0b708bd59f205d6b35cb2a8c24d62f0c33d77 /source/Plugins/SymbolFile/NativePDB
parent39be7ce23363d12ae3e49aeb1fdb2bfeb892e836 (diff)
downloadsrc-94994d372d014ce4c8758b9605d63fae651bd8aa.tar.gz
src-94994d372d014ce4c8758b9605d63fae651bd8aa.zip
Vendor import of lldb trunk r351319 (just before the release_80 branchvendor/lldb/lldb-trunk-r351319
Notes
Notes: svn path=/vendor/lldb/dist/; revision=343181 svn path=/vendor/lldb/lldb-trunk-r351319/; revision=343182; tag=vendor/lldb/lldb-trunk-r351319
Diffstat (limited to 'source/Plugins/SymbolFile/NativePDB')
-rw-r--r--source/Plugins/SymbolFile/NativePDB/CMakeLists.txt21
-rw-r--r--source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp217
-rw-r--r--source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h95
-rw-r--r--source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp673
-rw-r--r--source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h42
-rw-r--r--source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp1348
-rw-r--r--source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h144
-rw-r--r--source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp200
-rw-r--r--source/Plugins/SymbolFile/NativePDB/PdbIndex.h162
-rw-r--r--source/Plugins/SymbolFile/NativePDB/PdbSymUid.cpp161
-rw-r--r--source/Plugins/SymbolFile/NativePDB/PdbSymUid.h126
-rw-r--r--source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp750
-rw-r--r--source/Plugins/SymbolFile/NativePDB/PdbUtil.h159
-rw-r--r--source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp1571
-rw-r--r--source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h245
-rw-r--r--source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp191
-rw-r--r--source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h75
17 files changed, 6180 insertions, 0 deletions
diff --git a/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt b/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt
new file mode 100644
index 000000000000..da2d7fe8108a
--- /dev/null
+++ b/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt
@@ -0,0 +1,21 @@
+add_lldb_library(lldbPluginSymbolFileNativePDB PLUGIN
+ CompileUnitIndex.cpp
+ DWARFLocationExpression.cpp
+ PdbAstBuilder.cpp
+ PdbIndex.cpp
+ PdbSymUid.cpp
+ PdbUtil.cpp
+ SymbolFileNativePDB.cpp
+ UdtRecordCompleter.cpp
+
+ LINK_LIBS
+ clangAST
+ clangLex
+ lldbCore
+ lldbSymbol
+ lldbUtility
+ LINK_COMPONENTS
+ DebugInfoCodeView
+ DebugInfoPDB
+ Support
+ )
diff --git a/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp b/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp
new file mode 100644
index 000000000000..67ea05767fde
--- /dev/null
+++ b/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp
@@ -0,0 +1,217 @@
+//===-- CompileUnitIndex.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#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_lower(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();
+ llvm::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;
+ }
+}
+
+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);
+ llvm::pdb::ModuleDebugStreamRef debug_stream(descriptor,
+ std::move(stream_data));
+ cantFail(debug_stream.reload());
+
+ std::unique_ptr<CompilandIndexItem> &cci = result.first->second;
+
+ cci = llvm::make_unique<CompilandIndexItem>(
+ PdbCompilandId{modi}, std::move(debug_stream), std::move(descriptor));
+ ParseExtendedInfo(m_index, *cci);
+
+ cci->m_strings.initialize(debug_stream.getSubsectionsArray());
+ PDBStringTable &strings = cantFail(m_index.pdb().getStringTable());
+ cci->m_strings.setStrings(strings.getStringTable());
+
+ // 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 = 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.startswith("/")
+ ? 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/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h b/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h
new file mode 100644
index 000000000000..c965870da44b
--- /dev/null
+++ b/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h
@@ -0,0 +1,95 @@
+//===-- CompileUnitIndex.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_PLUGINS_SYMBOLFILENATIVEPDB_COMPILEUNITINDEX_H
+#define LLDB_PLUGINS_SYMBOLFILENATIVEPDB_COMPILEUNITINDEX_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/IntervalMap.h"
+#include "llvm/ADT/Optional.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>
+
+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.
+ llvm::Optional<llvm::codeview::Compile3Sym> m_compile_opts;
+
+ // S_OBJNAME sym describing object name.
+ llvm::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;
+};
+
+/// 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/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp b/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp
new file mode 100644
index 000000000000..7b62530e4680
--- /dev/null
+++ b/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp
@@ -0,0 +1,673 @@
+//===-- DWARFLocationExpression.cpp -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFLocationExpression.h"
+
+#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/StreamBuffer.h"
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/DataBufferHeap.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"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::npdb;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+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 GetLLDBRegisterNumber(llvm::Triple::ArchType arch_type,
+ llvm::codeview::RegisterId register_id) {
+ switch (arch_type) {
+ 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 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(nullptr);
+
+ RegisterKind register_kind = eRegisterKindDWARF;
+ StreamBuffer<32> stream(Stream::eBinary, address_size, byte_order);
+
+ if (!writer(stream, register_kind))
+ return DWARFExpression(nullptr);
+
+ DataBufferSP buffer =
+ std::make_shared<DataBufferHeap>(stream.GetData(), stream.GetSize());
+ DataExtractor extractor(buffer, byte_order, address_size, byte_size);
+ DWARFExpression result(module, extractor, nullptr, 0, buffer->GetByteSize());
+ result.SetRegisterKind(register_kind);
+
+ return result;
+}
+
+static DWARFExpression MakeRegisterBasedLocationExpressionInternal(
+ llvm::codeview::RegisterId reg, llvm::Optional<int32_t> relative_offset,
+ lldb::ModuleSP module) {
+ return MakeLocationExpressionInternal(
+ module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
+ 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;
+ });
+}
+
+DWARFExpression lldb_private::npdb::MakeEnregisteredLocationExpression(
+ llvm::codeview::RegisterId reg, lldb::ModuleSP module) {
+ return MakeRegisterBasedLocationExpressionInternal(reg, llvm::None, module);
+}
+
+DWARFExpression lldb_private::npdb::MakeRegRelLocationExpression(
+ llvm::codeview::RegisterId reg, int32_t offset, lldb::ModuleSP module) {
+ return MakeRegisterBasedLocationExpressionInternal(reg, offset, module);
+}
+
+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);
+
+ // Section indices in PDB are 1-based, but in DWARF they are 0-based, so
+ // we need to subtract 1.
+ uint32_t section_idx = section - 1;
+ if (section_idx >= section_list->GetSize())
+ return false;
+
+ auto section_ptr = section_list->GetSectionAtIndex(section_idx);
+ 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::makeArrayRef(reinterpret_cast<const uint8_t *>(&Value), 8)
+ .take_front(size);
+ buffer->CopyData(bytes.data(), size);
+ DataExtractor extractor(buffer, lldb::eByteOrderLittle, address_size);
+ DWARFExpression result(nullptr, extractor, nullptr, 0, size);
+ return result;
+}
diff --git a/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h b/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h
new file mode 100644
index 000000000000..670e95ee8e3c
--- /dev/null
+++ b/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h
@@ -0,0 +1,42 @@
+//===-- DWARFLocationExpression.h -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_DWARFLOCATIONEXPRESSION_H
+#define LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_DWARFLOCATIONEXPRESSION_H
+
+#include "lldb/lldb-forward.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+
+namespace llvm {
+class APSInt;
+namespace codeview {
+class TypeIndex;
+}
+namespace pdb {
+class TpiStream;
+}
+} // namespace llvm
+namespace lldb_private {
+namespace npdb {
+DWARFExpression
+MakeEnregisteredLocationExpression(llvm::codeview::RegisterId reg,
+ lldb::ModuleSP module);
+
+DWARFExpression MakeRegRelLocationExpression(llvm::codeview::RegisterId reg,
+ 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);
+} // namespace npdb
+} // namespace lldb_private
+
+#endif
diff --git a/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp b/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
new file mode 100644
index 000000000000..8917fd092385
--- /dev/null
+++ b/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
@@ -0,0 +1,1348 @@
+#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 "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/ClangExternalASTSourceCommon.h"
+#include "lldb/Symbol/ClangUtil.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Utility/LLDBAssert.h"
+
+#include "PdbUtil.h"
+#include "UdtRecordCompleter.h"
+
+using namespace lldb_private;
+using namespace lldb_private::npdb;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+static llvm::Optional<PdbCompilandSymId> FindSymbolScope(PdbIndex &index,
+ PdbCompilandSymId id) {
+ CVSymbol sym = 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 llvm::None to indicate
+ // this.
+ if (id.offset == 0)
+ return llvm::None;
+ return id;
+ }
+
+ // Otherwise we need to start at the beginning and iterate forward until we
+ // reach (or pass) this particular symbol
+ CompilandIndexItem &cii = 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 (id.offset == begin.offset()) {
+ // We have a match! Return the top of the stack
+ if (scope_stack.empty())
+ return llvm::None;
+ return scope_stack.back();
+ }
+ if (begin.offset() > id.offset) {
+ // We passed it. We couldn't even find this symbol record.
+ lldbassert(false && "Invalid compiland symbol id!");
+ return llvm::None;
+ }
+
+ // 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.modi) {
+ 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;
+ }
+
+ return llvm::None;
+}
+
+static clang::TagTypeKind TranslateUdtKind(const TagRecord &cr) {
+ switch (cr.Kind) {
+ case TypeRecordKind::Class:
+ return clang::TTK_Class;
+ case TypeRecordKind::Struct:
+ return clang::TTK_Struct;
+ case TypeRecordKind::Union:
+ return clang::TTK_Union;
+ case TypeRecordKind::Interface:
+ return clang::TTK_Interface;
+ case TypeRecordKind::Enum:
+ return clang::TTK_Enum;
+ default:
+ lldbassert(false && "Invalid tag record kind!");
+ return clang::TTK_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 ClangASTContext &GetClangASTContext(ObjectFile &obj) {
+ TypeSystem *ts =
+ obj.GetModule()->GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
+ lldbassert(ts);
+ return static_cast<ClangASTContext &>(*ts);
+}
+
+static llvm::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 llvm::None;
+ }
+}
+
+static llvm::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 llvm::None;
+
+ CVType cvt = tpi.getType(Record.Type);
+
+ if (!IsTagRecord(cvt))
+ return llvm::None;
+
+ // 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 = parent.asTag().getUniqueName();
+ if (qname.size() < 4 || child.asTag().getUniqueName().size() < 4)
+ return llvm::None;
+
+ // 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 llvm::None;
+
+ return std::move(child);
+}
+
+PdbAstBuilder::PdbAstBuilder(ObjectFile &obj, PdbIndex &index)
+ : m_index(index), m_clang(GetClangASTContext(obj)) {
+ BuildParentMap();
+}
+
+clang::DeclContext &PdbAstBuilder::GetTranslationUnitDecl() {
+ return *m_clang.GetTranslationUnitDecl();
+}
+
+std::pair<clang::DeclContext *, std::string>
+PdbAstBuilder::CreateDeclInfoForType(const TagRecord &record, TypeIndex ti) {
+ // FIXME: Move this to GetDeclContextContainingUID.
+ if (!record.hasUniqueName())
+ return CreateDeclInfoForUndecoratedName(record.Name);
+
+ llvm::ms_demangle::Demangler demangler;
+ StringView sv(record.UniqueName.begin(), record.UniqueName.size());
+ llvm::ms_demangle::TagTypeNode *ttn = demangler.parseTagUniqueName(sv);
+ if (demangler.Error)
+ return {m_clang.GetTranslationUnitDecl(), 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).
+ auto parent_iter = m_parent_types.find(ti);
+ if (parent_iter == m_parent_types.end()) {
+ 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, record.Name};
+
+ for (llvm::ms_demangle::Node *scope : scopes) {
+ auto *nii = static_cast<llvm::ms_demangle::NamedIdentifierNode *>(scope);
+ std::string str = nii->toString();
+ context = m_clang.GetUniqueNamespaceDeclaration(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_iter->second);
+
+ context = clang::TagDecl::castToDeclContext(parent_qt->getAsTagDecl());
+ return {context, uname};
+}
+
+void PdbAstBuilder::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;
+ }
+ llvm::Optional<CVTagRecord> tag =
+ GetNestedTagDefinition(Record, parent_cvt, index.tpi());
+ if (!tag)
+ return llvm::ErrorSuccess();
+
+ parents[Record.Type] = parent;
+ return llvm::ErrorSuccess();
+ }
+ };
+
+ CVType field_list = m_index.tpi().getType(tag.asTag().FieldList);
+ ProcessTpiStream process(m_index, *ti, tag, m_parent_types);
+ llvm::Error error = visitMemberRecordStream(field_list.data(), process);
+ if (error)
+ 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];
+ m_parent_types[full] = m_parent_types[fwd];
+ }
+ for (TypeIndex full : full_keys) {
+ TypeIndex fwd = full_to_forward[full];
+ m_parent_types[fwd] = m_parent_types[full];
+ }
+
+ // Now that
+}
+
+static bool isLocalVariableType(SymbolKind K) {
+ switch (K) {
+ case S_REGISTER:
+ case S_REGREL32:
+ case S_LOCAL:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+static std::string
+RenderScopeList(llvm::ArrayRef<llvm::ms_demangle::Node *> nodes) {
+ lldbassert(!nodes.empty());
+
+ std::string result = nodes.front()->toString();
+ nodes = nodes.drop_front();
+ while (!nodes.empty()) {
+ result += "::";
+ result += nodes.front()->toString(llvm::ms_demangle::OF_NoTagSpecifier);
+ nodes = nodes.drop_front();
+ }
+ return result;
+}
+
+static llvm::Optional<PublicSym32> FindPublicSym(const SegmentOffset &addr,
+ SymbolStream &syms,
+ PublicsStream &publics) {
+ llvm::FixedStreamArray<ulittle32_t> addr_map = publics.getAddressMap();
+ auto iter = std::lower_bound(
+ addr_map.begin(), addr_map.end(), addr,
+ [&](const ulittle32_t &x, const SegmentOffset &y) {
+ CVSymbol s1 = syms.readRecord(x);
+ lldbassert(s1.kind() == S_PUB32);
+ PublicSym32 p1;
+ llvm::cantFail(SymbolDeserializer::deserializeAs<PublicSym32>(s1, p1));
+ if (p1.Segment < y.segment)
+ return true;
+ return p1.Offset < y.offset;
+ });
+ if (iter == addr_map.end())
+ return llvm::None;
+ CVSymbol sym = syms.readRecord(*iter);
+ lldbassert(sym.kind() == S_PUB32);
+ PublicSym32 p;
+ llvm::cantFail(SymbolDeserializer::deserializeAs<PublicSym32>(sym, p));
+ if (p.Segment == addr.segment && p.Offset == addr.offset)
+ return p;
+ return llvm::None;
+}
+
+clang::Decl *PdbAstBuilder::GetOrCreateSymbolForId(PdbCompilandSymId id) {
+ CVSymbol cvs = m_index.ReadSymbolRecord(id);
+
+ if (isLocalVariableType(cvs.kind())) {
+ clang::DeclContext *scope = GetParentDeclContext(id);
+ clang::Decl *scope_decl = clang::Decl::castFromDeclContext(scope);
+ PdbCompilandSymId scope_id(id.modi, m_decl_to_status[scope_decl].uid);
+ 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);
+ default:
+ return nullptr;
+ }
+}
+
+clang::Decl *PdbAstBuilder::GetOrCreateDeclForUid(PdbSymUid uid) {
+ if (clang::Decl *result = TryGetDecl(uid))
+ return 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 (auto *tag = qt->getAsTagDecl()) {
+ result = tag;
+ break;
+ }
+ return nullptr;
+ }
+ default:
+ return nullptr;
+ }
+ m_uid_to_decl[toOpaqueUid(uid)] = result;
+ return result;
+}
+
+clang::DeclContext *PdbAstBuilder::GetOrCreateDeclContextForUid(PdbSymUid uid) {
+ if (uid.kind() == PdbSymUidKind::CompilandSym) {
+ if (uid.asCompilandSym().offset == 0)
+ return &GetTranslationUnitDecl();
+ }
+
+ clang::Decl *decl = GetOrCreateDeclForUid(uid);
+ if (!decl)
+ return nullptr;
+
+ return clang::Decl::castToDeclContext(decl);
+}
+
+std::pair<clang::DeclContext *, std::string>
+PdbAstBuilder::CreateDeclInfoForUndecoratedName(llvm::StringRef name) {
+ MSVCUndecoratedNameParser parser(name);
+ llvm::ArrayRef<MSVCUndecoratedNameSpecifier> specs = parser.GetSpecifiers();
+
+ clang::DeclContext *context = &GetTranslationUnitDecl();
+
+ llvm::StringRef uname = specs.back().GetBaseName();
+ specs = specs.drop_back();
+ if (specs.empty())
+ return {context, name};
+
+ llvm::StringRef scope_name = specs.back().GetFullName();
+
+ // It might be a class name, try that first.
+ std::vector<TypeIndex> types = m_index.tpi().findRecordsByName(scope_name);
+ while (!types.empty()) {
+ clang::QualType qt = GetOrCreateType(types.back());
+ clang::TagDecl *tag = qt->getAsTagDecl();
+ if (tag)
+ return {clang::TagDecl::castToDeclContext(tag), 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 = m_clang.GetUniqueNamespaceDeclaration(ns_name.c_str(), context);
+ }
+ return {context, uname};
+}
+
+clang::DeclContext *
+PdbAstBuilder::GetParentDeclContextForSymbol(const CVSymbol &sym) {
+ if (!SymbolHasAddress(sym))
+ return CreateDeclInfoForUndecoratedName(getSymbolName(sym)).first;
+ SegmentOffset addr = GetSegmentAndOffset(sym);
+ llvm::Optional<PublicSym32> pub =
+ FindPublicSym(addr, m_index.symrecords(), m_index.publics());
+ if (!pub)
+ return CreateDeclInfoForUndecoratedName(getSymbolName(sym)).first;
+
+ llvm::ms_demangle::Demangler demangler;
+ StringView name{pub->Name.begin(), pub->Name.size()};
+ llvm::ms_demangle::SymbolNode *node = demangler.parse(name);
+ if (!node)
+ return &GetTranslationUnitDecl();
+ llvm::ArrayRef<llvm::ms_demangle::Node *> name_components{
+ node->Name->Components->Nodes, node->Name->Components->Count - 1};
+
+ if (!name_components.empty()) {
+ // Render the current list of scope nodes as a fully qualified name, and
+ // look it up in the debug info as a type name. If we find something,
+ // this is a type (which may itself be prefixed by a namespace). If we
+ // don't, this is a list of namespaces.
+ std::string qname = RenderScopeList(name_components);
+ std::vector<TypeIndex> matches = m_index.tpi().findRecordsByName(qname);
+ while (!matches.empty()) {
+ clang::QualType qt = GetOrCreateType(matches.back());
+ clang::TagDecl *tag = qt->getAsTagDecl();
+ if (tag)
+ return clang::TagDecl::castToDeclContext(tag);
+ matches.pop_back();
+ }
+ }
+
+ // It's not a type. It must be a series of namespaces.
+ clang::DeclContext *context = &GetTranslationUnitDecl();
+ while (!name_components.empty()) {
+ std::string ns = name_components.front()->toString();
+ context = m_clang.GetUniqueNamespaceDeclaration(ns.c_str(), context);
+ name_components = name_components.drop_front();
+ }
+ return context;
+}
+
+clang::DeclContext *PdbAstBuilder::GetParentDeclContext(PdbSymUid uid) {
+ // We must do this *without* calling GetOrCreate on the current uid, as
+ // that would be an infinite recursion.
+ switch (uid.kind()) {
+ case PdbSymUidKind::CompilandSym: {
+ llvm::Optional<PdbCompilandSymId> scope =
+ FindSymbolScope(m_index, uid.asCompilandSym());
+ if (scope)
+ return GetOrCreateDeclContextForUid(*scope);
+
+ CVSymbol sym = m_index.ReadSymbolRecord(uid.asCompilandSym());
+ return GetParentDeclContextForSymbol(sym);
+ }
+ 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();
+ auto iter = m_parent_types.find(type_id.index);
+ if (iter == m_parent_types.end())
+ return &GetTranslationUnitDecl();
+ return GetOrCreateDeclContextForUid(PdbTypeSymId(iter->second));
+ }
+ 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 = m_index.ReadSymbolRecord(uid.asGlobalSym());
+ switch (global.kind()) {
+ case SymbolKind::S_GDATA32:
+ case SymbolKind::S_LDATA32:
+ return GetParentDeclContextForSymbol(global);
+ 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 &GetTranslationUnitDecl();
+}
+
+bool PdbAstBuilder::CompleteType(clang::QualType qt) {
+ clang::TagDecl *tag = qt->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();
+
+ lldbassert(IsTagRecord(type_id, m_index.tpi()));
+
+ clang::QualType tag_qt = m_clang.getASTContext()->getTypeDeclType(&tag);
+ ClangASTContext::SetHasExternalStorage(tag_qt.getAsOpaquePtr(), false);
+
+ TypeIndex tag_ti = type_id.index;
+ CVType cvt = m_index.tpi().getType(tag_ti);
+ if (cvt.kind() == LF_MODIFIER)
+ tag_ti = LookThroughModifierRecord(cvt);
+
+ PdbTypeSymId best_ti = GetBestPossibleDecl(tag_ti, m_index.tpi());
+ cvt = m_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 = m_index.tpi().getType(field_list_ti);
+ if (field_list_cvt.kind() != LF_FIELDLIST)
+ return false;
+
+ // 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, m_index.tpi());
+ auto error =
+ llvm::codeview::visitMemberRecordStream(field_list_cvt.data(), completer);
+ completer.complete();
+
+ status.resolved = true;
+ if (!error)
+ return true;
+
+ llvm::consumeError(std::move(error));
+ return false;
+}
+
+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());
+ 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);
+
+ 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);
+ clang::TagTypeKind ttk = TranslateUdtKind(record);
+ lldb::AccessType access =
+ (ttk == clang::TTK_Class) ? lldb::eAccessPrivate : lldb::eAccessPublic;
+
+ ClangASTMetadata metadata;
+ metadata.SetUserID(toOpaqueUid(id));
+ metadata.SetIsDynamicCXXType(false);
+
+ CompilerType ct =
+ m_clang.CreateRecordType(context, access, uname.c_str(), ttk,
+ lldb::eLanguageTypeC_plus_plus, &metadata);
+
+ lldbassert(ct.IsValid());
+
+ ClangASTContext::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());
+
+ ClangASTContext::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(llvm::StringRef name,
+ clang::DeclContext &context) {
+ return m_clang.GetUniqueNamespaceDeclaration(name.str().c_str(), &context);
+}
+
+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);
+ 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);
+
+ clang::VarDecl *var_decl = m_clang.CreateVariableDeclaration(
+ &scope, 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);
+
+ CVSymbol sym = m_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);
+
+ CVSymbol sym = m_index.ReadSymbolRecord(var_id);
+ return CreateVariableDecl(PdbSymUid(var_id), sym, GetTranslationUnitDecl());
+}
+
+clang::TypedefNameDecl *
+PdbAstBuilder::GetOrCreateTypedefDecl(PdbGlobalSymId id) {
+ if (clang::Decl *decl = TryGetDecl(id))
+ return llvm::dyn_cast<clang::TypedefNameDecl>(decl);
+
+ CVSymbol sym = m_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);
+
+ std::string uname = DropNameScope(udt.Name);
+
+ CompilerType ct = m_clang.CreateTypedefType(ToCompilerType(qt), uname.c_str(),
+ ToCompilerDeclContext(*scope));
+ 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);
+
+ CVType cvt = m_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 CreateProcedureType(pr);
+ }
+
+ return {};
+}
+
+clang::QualType PdbAstBuilder::GetOrCreateType(PdbTypeSymId type) {
+ 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;
+
+ PdbTypeSymId best_type = GetBestPossibleDecl(type, m_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);
+ 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);
+ m_uid_to_type[toOpaqueUid(type)] = qt;
+ if (IsTagRecord(type, m_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::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));
+ 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();
+ }
+
+ CVSymbol cvs = m_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 = m_clang.CreateFunctionDeclaration(
+ parent, proc_name.str().c_str(), func_ct, storage, false);
+
+ 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});
+
+ CreateFunctionParameters(func_id, *function_decl, func_type->getNumParams());
+
+ return function_decl;
+}
+
+void PdbAstBuilder::CreateFunctionParameters(PdbCompilandSymId func_id,
+ clang::FunctionDecl &function_decl,
+ uint32_t param_count) {
+ CompilandIndexItem *cii = m_index.compilands().GetCompiland(func_id.modi);
+ CVSymbolArray scope =
+ cii->m_debug_stream.getSymbolArrayForScope(func_id.offset);
+
+ auto begin = scope.begin();
+ auto end = scope.end();
+ std::vector<clang::ParmVarDecl *> params;
+ while (begin != end && param_count > 0) {
+ 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:
+ // All parameters should come before the first block. 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);
+
+ CompilerType param_type_ct(&m_clang, qt.getAsOpaquePtr());
+ clang::ParmVarDecl *param = m_clang.CreateParameterDeclaration(
+ &function_decl, param_name.str().c_str(), param_type_ct,
+ clang::SC_None);
+ lldbassert(m_uid_to_decl.count(toOpaqueUid(param_uid)) == 0);
+
+ m_uid_to_decl[toOpaqueUid(param_uid)] = param;
+ params.push_back(param);
+ --param_count;
+ }
+
+ if (!params.empty())
+ m_clang.SetFunctionParameters(&function_decl, params.data(), params.size());
+}
+
+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);
+ clang::QualType underlying_type = GetOrCreateType(er.UnderlyingType);
+
+ Declaration declaration;
+ CompilerType enum_ct = m_clang.CreateEnumerationType(
+ uname.c_str(), decl_context, declaration, ToCompilerType(underlying_type),
+ er.isScoped());
+
+ ClangASTContext::StartTagDeclarationDefinition(enum_ct);
+ ClangASTContext::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);
+
+ uint64_t element_count =
+ ar.Size / GetSizeOfType({ar.ElementType}, m_index.tpi());
+
+ CompilerType array_ct = m_clang.CreateArrayType(ToCompilerType(element_type),
+ element_count, false);
+ return clang::QualType::getFromOpaquePtr(array_ct.GetOpaqueQualType());
+}
+
+clang::QualType
+PdbAstBuilder::CreateProcedureType(const ProcedureRecord &proc) {
+ TpiStream &stream = m_index.tpi();
+ CVType args_cvt = stream.getType(proc.ArgumentList);
+ ArgListRecord args;
+ llvm::cantFail(
+ TypeDeserializer::deserializeAs<ArgListRecord>(args_cvt, args));
+
+ llvm::ArrayRef<TypeIndex> arg_indices = llvm::makeArrayRef(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);
+ arg_types.push_back(ToCompilerType(arg_type));
+ }
+
+ clang::QualType return_type = GetOrCreateType(proc.ReturnType);
+
+ llvm::Optional<clang::CallingConv> cc =
+ TranslateCallingConvention(proc.CallConv);
+ 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::dyn_cast<clang::TagDecl>(&context);
+}
+
+static bool isFunctionDecl(clang::DeclContext &context) {
+ return !!llvm::dyn_cast<clang::FunctionDecl>(&context);
+}
+
+static bool isBlockDecl(clang::DeclContext &context) {
+ return !!llvm::dyn_cast<clang::BlockDecl>(&context);
+}
+
+void PdbAstBuilder::ParseAllNamespacesPlusChildrenOf(
+ llvm::Optional<llvm::StringRef> parent) {
+ TypeIndex ti{m_index.tpi().TypeIndexBegin()};
+ for (const CVType &cvt : m_index.tpi().typeArray()) {
+ PdbTypeSymId tid{ti};
+ ++ti;
+
+ if (!IsTagRecord(cvt))
+ continue;
+
+ CVTagRecord tag = CVTagRecord::create(cvt);
+
+ if (!parent.hasValue()) {
+ clang::QualType qt = GetOrCreateType(tid);
+ CompleteType(qt);
+ continue;
+ }
+
+ // 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->isNamespace())
+ continue;
+
+ clang::NamespaceDecl *ns = llvm::dyn_cast<clang::NamespaceDecl>(context);
+ std::string actual_ns = ns->getQualifiedNameAsString();
+ if (llvm::StringRef(actual_ns).startswith(*parent)) {
+ clang::QualType qt = GetOrCreateType(tid);
+ CompleteType(qt);
+ continue;
+ }
+ }
+
+ uint32_t module_count = m_index.dbi().modules().getModuleCount();
+ for (uint16_t modi = 0; modi < module_count; ++modi) {
+ CompilandIndexItem &cii = m_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) {
+ CVSymbol sym = m_index.ReadSymbolRecord(block_id);
+ lldbassert(sym.kind() == S_GPROC32 || sym.kind() == S_LPROC32 ||
+ sym.kind() == S_BLOCK32);
+ CompilandIndexItem &cii =
+ m_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);
+
+ 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) {
+ 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()) {
+ ParseAllNamespacesPlusChildrenOf(llvm::None);
+ return;
+ }
+
+ if (context.isNamespace()) {
+ clang::NamespaceDecl &ns = *llvm::dyn_cast<clang::NamespaceDecl>(&context);
+ std::string qname = ns.getQualifiedNameAsString();
+ ParseAllNamespacesPlusChildrenOf(llvm::StringRef{qname});
+ return;
+ }
+
+ if (isTagDecl(context) || isFunctionDecl(context) || isBlockDecl(context)) {
+ ParseDeclsForSimpleContext(context);
+ return;
+ }
+}
+
+CompilerDecl PdbAstBuilder::ToCompilerDecl(clang::Decl &decl) {
+ return {&m_clang, &decl};
+}
+
+CompilerType PdbAstBuilder::ToCompilerType(clang::QualType qt) {
+ return {&m_clang, qt.getAsOpaquePtr()};
+}
+
+CompilerDeclContext
+PdbAstBuilder::ToCompilerDeclContext(clang::DeclContext &context) {
+ return {&m_clang, &context};
+}
+
+clang::DeclContext *
+PdbAstBuilder::FromCompilerDeclContext(CompilerDeclContext context) {
+ return static_cast<clang::DeclContext *>(context.GetOpaqueDeclContext());
+}
+
+void PdbAstBuilder::Dump(Stream &stream) { m_clang.Dump(stream); }
diff --git a/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h b/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h
new file mode 100644
index 000000000000..e3c0346f935e
--- /dev/null
+++ b/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h
@@ -0,0 +1,144 @@
+//===-- PdbAstBuilder.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBASTBUILDER_H
+#define LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBASTBUILDER_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
+
+#include "lldb/Symbol/ClangASTImporter.h"
+
+#include "PdbIndex.h"
+#include "PdbSymUid.h"
+
+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(ObjectFile &obj, PdbIndex &index);
+
+ clang::DeclContext &GetTranslationUnitDecl();
+
+ clang::Decl *GetOrCreateDeclForUid(PdbSymUid uid);
+ clang::DeclContext *GetOrCreateDeclContextForUid(PdbSymUid uid);
+ clang::DeclContext *GetParentDeclContext(PdbSymUid uid);
+
+ clang::NamespaceDecl *GetOrCreateNamespaceDecl(llvm::StringRef name,
+ clang::DeclContext &context);
+ clang::FunctionDecl *GetOrCreateFunctionDecl(PdbCompilandSymId func_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::DeclContext *FromCompilerDeclContext(CompilerDeclContext context);
+
+ ClangASTContext &clang() { return m_clang; }
+ ClangASTImporter &importer() { 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
+ CreateProcedureType(const llvm::codeview::ProcedureRecord &proc);
+ 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::DeclContext *
+ GetParentDeclContextForSymbol(const llvm::codeview::CVSymbol &sym);
+
+ void ParseAllNamespacesPlusChildrenOf(llvm::Optional<llvm::StringRef> parent);
+ void ParseDeclsForSimpleContext(clang::DeclContext &context);
+ void ParseBlockChildren(PdbCompilandSymId block_id);
+
+ void BuildParentMap();
+ 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);
+
+ PdbIndex &m_index;
+ ClangASTContext &m_clang;
+
+ ClangASTImporter m_importer;
+
+ llvm::DenseMap<TypeIndex, TypeIndex> m_parent_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;
+};
+
+} // namespace npdb
+} // namespace lldb_private
+
+#endif // lldb_Plugins_SymbolFile_PDB_SymbolFilePDB_h_
diff --git a/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp b/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp
new file mode 100644
index 000000000000..9f5dab6c2e84
--- /dev/null
+++ b/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp
@@ -0,0 +1,200 @@
+//===-- PdbIndex.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#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"
+
+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(std::unique_ptr<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 = std::move(file);
+
+ return std::move(result);
+}
+
+lldb::addr_t PdbIndex::MakeVirtualAddress(uint16_t segment,
+ uint32_t offset) const {
+ // Segment indices are 1-based.
+ lldbassert(segment > 0);
+
+ uint32_t max_section = dbi().getSectionHeaders().size();
+ lldbassert(segment <= max_section + 1);
+
+ // 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 == max_section + 1)
+ 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);
+}
+
+lldb::addr_t PdbIndex::MakeVirtualAddress(const SegmentOffset &so) const {
+ return MakeVirtualAddress(so.segment, so.offset);
+}
+
+llvm::Optional<uint16_t>
+PdbIndex::GetModuleIndexForAddr(uint16_t segment, uint32_t offset) const {
+ return GetModuleIndexForVa(MakeVirtualAddress(segment, offset));
+}
+
+llvm::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 llvm::None;
+
+ 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);
+ 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);
+
+ PdbCompilandSymId cu_sym_id(modi, iter.offset());
+
+ // If the debug info is incorrect, we could have multiple symbols with the
+ // same address. So use try_emplace instead of insert, and 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;
+
+ llvm::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);
+ 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 {
+ // We need to subtract 4 here to adjust for the codeview debug magic
+ // at the beginning of the debug info stream.
+ 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/source/Plugins/SymbolFile/NativePDB/PdbIndex.h b/source/Plugins/SymbolFile/NativePDB/PdbIndex.h
new file mode 100644
index 000000000000..839d4e6606e4
--- /dev/null
+++ b/source/Plugins/SymbolFile/NativePDB/PdbIndex.h
@@ -0,0 +1,162 @@
+//===-- PdbIndex.h ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_PLUGINS_SYMBOLFILENATIVEPDB_PDBINDEX_H
+#define LLDB_PLUGINS_SYMBOLFILENATIVEPDB_PDBINDEX_H
+
+#include "lldb/lldb-types.h"
+#include "llvm/ADT/IntervalMap.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/PDBTypes.h"
+
+#include "CompileUnitIndex.h"
+#include "PdbSymUid.h"
+
+#include <map>
+#include <memory>
+
+namespace llvm {
+namespace pdb {
+class DbiStream;
+class TpiStream;
+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.
+ std::unique_ptr<llvm::pdb::PDBFile> m_file;
+
+ /// 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(std::unique_ptr<llvm::pdb::PDBFile>);
+
+ void SetLoadAddress(lldb::addr_t addr) { m_load_address = addr; }
+ 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;
+ lldb::addr_t MakeVirtualAddress(const SegmentOffset &so) const;
+
+ std::vector<SymbolAndUid> FindSymbolsByVa(lldb::addr_t va);
+
+ llvm::codeview::CVSymbol ReadSymbolRecord(PdbCompilandSymId cu_sym) const;
+ llvm::codeview::CVSymbol ReadSymbolRecord(PdbGlobalSymId global) const;
+
+ llvm::Optional<uint16_t> GetModuleIndexForAddr(uint16_t segment,
+ uint32_t offset) const;
+ llvm::Optional<uint16_t> GetModuleIndexForVa(lldb::addr_t va) const;
+};
+} // namespace npdb
+} // namespace lldb_private
+
+#endif
diff --git a/source/Plugins/SymbolFile/NativePDB/PdbSymUid.cpp b/source/Plugins/SymbolFile/NativePDB/PdbSymUid.cpp
new file mode 100644
index 000000000000..e5424568da47
--- /dev/null
+++ b/source/Plugins/SymbolFile/NativePDB/PdbSymUid.cpp
@@ -0,0 +1,161 @@
+//===-- PdbSymUid.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#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/source/Plugins/SymbolFile/NativePDB/PdbSymUid.h b/source/Plugins/SymbolFile/NativePDB/PdbSymUid.h
new file mode 100644
index 000000000000..1166bee4e327
--- /dev/null
+++ b/source/Plugins/SymbolFile/NativePDB/PdbSymUid.h
@@ -0,0 +1,126 @@
+//===-- PdbSymUid.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// 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_PLUGINS_SYMBOLFILENATIVEPDB_PDBSYMUID_H
+#define LLDB_PLUGINS_SYMBOLFILENATIVEPDB_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/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp b/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
new file mode 100644
index 000000000000..317725dd250e
--- /dev/null
+++ b/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
@@ -0,0 +1,750 @@
+//===-- PdbUtil.cpp ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PdbUtil.h"
+
+#include "DWARFLocationExpression.h"
+#include "PdbIndex.h"
+#include "PdbSymUid.h"
+
+#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+
+#include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/lldb-enumerations.h"
+
+using namespace lldb_private;
+using namespace lldb_private::npdb;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+static Variable::RangeList
+MakeRangeList(const PdbIndex &index, const LocalVariableAddrRange &range,
+ llvm::ArrayRef<LocalVariableAddrGap> gaps) {
+ lldb::addr_t start =
+ index.MakeVirtualAddress(range.ISectStart, range.OffsetStart);
+ lldb::addr_t end = start + range.Range;
+
+ Variable::RangeList result;
+ while (!gaps.empty()) {
+ const LocalVariableAddrGap &gap = gaps.front();
+
+ lldb::addr_t size = gap.GapStartOffset - start;
+ result.Append(start, size);
+ start += gap.Range;
+ gaps = gaps.drop_front();
+ }
+
+ result.Append(start, end);
+ return result;
+}
+
+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;
+ 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 {};
+}
+
+VariableInfo lldb_private::npdb::GetVariableLocationInfo(
+ PdbIndex &index, PdbCompilandSymId var_id, 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 =
+ MakeRegRelLocationExpression(reg.Register, reg.Offset, module);
+ result.ranges.emplace();
+ return result;
+ }
+
+ if (sym.kind() == S_REGISTER) {
+ RegisterSym reg(SymbolRecordKind::RegisterSym);
+ cantFail(SymbolDeserializer::deserializeAs<RegisterSym>(sym, reg));
+ result.location = MakeEnregisteredLocationExpression(reg.Register, module);
+ result.ranges.emplace();
+ return result;
+ }
+
+ if (sym.kind() == S_LOCAL) {
+ LocalSym local(SymbolRecordKind::LocalSym);
+ cantFail(SymbolDeserializer::deserializeAs<LocalSym>(sym, local));
+
+ PdbCompilandSymId loc_specifier_id(var_id.modi,
+ var_id.offset + sym.RecordData.size());
+ CVSymbol loc_specifier_cvs = index.ReadSymbolRecord(loc_specifier_id);
+ if (loc_specifier_cvs.kind() == S_DEFRANGE_FRAMEPOINTER_REL) {
+ DefRangeFramePointerRelSym loc(
+ SymbolRecordKind::DefRangeFramePointerRelSym);
+ cantFail(SymbolDeserializer::deserializeAs<DefRangeFramePointerRelSym>(
+ loc_specifier_cvs, loc));
+ // FIXME: The register needs to come from the S_FRAMEPROC symbol.
+ result.location =
+ MakeRegRelLocationExpression(RegisterId::RSP, loc.Offset, module);
+ result.ranges = MakeRangeList(index, loc.Range, loc.Gaps);
+ } else {
+ // FIXME: Handle other kinds
+ }
+ 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::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:
+ 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);
+ default:
+ break;
+ }
+ return 0;
+}
diff --git a/source/Plugins/SymbolFile/NativePDB/PdbUtil.h b/source/Plugins/SymbolFile/NativePDB/PdbUtil.h
new file mode 100644
index 000000000000..570c300b6a2b
--- /dev/null
+++ b/source/Plugins/SymbolFile/NativePDB/PdbUtil.h
@@ -0,0 +1,159 @@
+//===-- PdbUtil.h -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_PLUGINS_SYMBOLFILENATIVEPDB_PDBUTIL_H
+#define LLDB_PLUGINS_SYMBOLFILENATIVEPDB_PDBUTIL_H
+
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/lldb-enumerations.h"
+
+#include "llvm/ADT/Optional.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;
+ llvm::Optional<DWARFExpression> location;
+ llvm::Optional<Variable::RangeList> ranges;
+};
+
+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,
+ 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/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
new file mode 100644
index 000000000000..7e97e2b37724
--- /dev/null
+++ b/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -0,0 +1,1571 @@
+//===-- SymbolFileNativePDB.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolFileNativePDB.h"
+
+#include "clang/AST/Attr.h"
+#include "clang/AST/CharUnits.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Type.h"
+
+#include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/StreamBuffer.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/ClangASTImporter.h"
+#include "lldb/Symbol/ClangExternalASTSourceCommon.h"
+#include "lldb/Symbol/ClangUtil.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 "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/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.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 "PdbAstBuilder.h"
+#include "PdbSymUid.h"
+#include "PdbUtil.h"
+#include "UdtRecordCompleter.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace npdb;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+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;
+ default:
+ return lldb::LanguageType::eLanguageTypeUnknown;
+ }
+}
+
+static std::unique_ptr<PDBFile> loadPDBFile(std::string PdbPath,
+ llvm::BumpPtrAllocator &Allocator) {
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ErrorOrBuffer =
+ llvm::MemoryBuffer::getFile(PdbPath, /*FileSize=*/-1,
+ /*RequiresNullTerminator=*/false);
+ if (!ErrorOrBuffer)
+ return nullptr;
+ std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(*ErrorOrBuffer);
+
+ llvm::StringRef Path = Buffer->getBufferIdentifier();
+ auto Stream = llvm::make_unique<llvm::MemoryBufferByteStream>(
+ std::move(Buffer), llvm::support::little);
+
+ auto File = llvm::make_unique<PDBFile>(Path, std::move(Stream), Allocator);
+ if (auto EC = File->parseFileHeaders()) {
+ llvm::consumeError(std::move(EC));
+ return nullptr;
+ }
+ if (auto EC = File->parseStreamData()) {
+ llvm::consumeError(std::move(EC));
+ return nullptr;
+ }
+
+ return File;
+}
+
+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);
+
+ 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;
+ auto ec = obj->getDebugPDBInfo(pdb_info, pdb_file);
+ if (ec)
+ return nullptr;
+
+ // if the file doesn't exist, is not a pdb, or doesn't have a matching guid,
+ // fail.
+ llvm::file_magic magic;
+ ec = llvm::identify_magic(pdb_file, magic);
+ if (ec || magic != llvm::file_magic::pdb)
+ return nullptr;
+ std::unique_ptr<PDBFile> pdb = loadPDBFile(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::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;
+ }
+}
+
+void SymbolFileNativePDB::Initialize() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(), CreateInstance,
+ DebuggerInitialize);
+}
+
+void SymbolFileNativePDB::Terminate() {
+ PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+void SymbolFileNativePDB::DebuggerInitialize(Debugger &debugger) {}
+
+ConstString SymbolFileNativePDB::GetPluginNameStatic() {
+ static ConstString g_name("native-pdb");
+ return g_name;
+}
+
+const char *SymbolFileNativePDB::GetPluginDescriptionStatic() {
+ return "Microsoft PDB debug symbol cross-platform file reader.";
+}
+
+SymbolFile *SymbolFileNativePDB::CreateInstance(ObjectFile *obj_file) {
+ return new SymbolFileNativePDB(obj_file);
+}
+
+SymbolFileNativePDB::SymbolFileNativePDB(ObjectFile *object_file)
+ : SymbolFile(object_file) {}
+
+SymbolFileNativePDB::~SymbolFileNativePDB() {}
+
+uint32_t SymbolFileNativePDB::CalculateAbilities() {
+ uint32_t abilities = 0;
+ if (!m_obj_file)
+ return 0;
+
+ if (!m_index) {
+ // Lazily load and match the PDB file, but only do this once.
+ std::unique_ptr<PDBFile> file_up =
+ loadMatchingPDBFile(m_obj_file->GetFileSpec().GetPath(), m_allocator);
+
+ if (!file_up) {
+ auto module_sp = m_obj_file->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;
+ file_up = loadPDBFile(symfile.GetPath(), m_allocator);
+ }
+
+ if (!file_up)
+ return 0;
+
+ auto expected_index = PdbIndex::create(std::move(file_up));
+ 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_obj_file->GetFileOffset();
+ m_index->SetLoadAddress(m_obj_load_address);
+ m_index->ParseSectionContribs();
+
+ TypeSystem *ts = m_obj_file->GetModule()->GetTypeSystemForLanguage(
+ lldb::eLanguageTypeC_plus_plus);
+ if (ts)
+ ts->SetSymbolFile(this);
+
+ m_ast = llvm::make_unique<PdbAstBuilder>(*m_obj_file, *m_index);
+}
+
+uint32_t SymbolFileNativePDB::GetNumCompileUnits() {
+ 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);
+
+ if (sym.kind() == S_GPROC32 || sym.kind() == S_LPROC32) {
+ // This is a function. It must be global. Creating the Function entry for
+ // it automatically creates a block for it.
+ CompUnitSP comp_unit = GetOrCreateCompileUnit(*cii);
+ return GetOrCreateFunction(block_id, *comp_unit)->GetBlock(false);
+ }
+
+ lldbassert(sym.kind() == 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);
+ lldb::user_id_t opaque_block_uid = toOpaqueUid(block_id);
+ BlockSP child_block = std::make_shared<Block>(opaque_block_uid);
+ parent_block.AddChild(child_block);
+
+ m_ast->GetOrCreateBlockDecl(block_id);
+
+ m_blocks.insert({opaque_block_uid, child_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);
+ 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);
+
+ m_ast->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(source_file_name);
+
+ CompUnitSP cu_sp =
+ std::make_shared<CompileUnit>(m_obj_file->GetModule(), nullptr, fs,
+ toOpaqueUid(cci.m_id), lang, optimized);
+
+ m_obj_file->GetModule()->GetSymbolVendor()->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 = GetSimpleTypeName(mr.ModifiedType.getSimpleKind());
+ else
+ name = computeTypeName(stream.typeCollection(), mr.ModifiedType);
+ Declaration decl;
+ lldb::TypeSP modified_type = GetOrCreateType(mr.ModifiedType);
+
+ return std::make_shared<Type>(toOpaqueUid(type_id), this, ConstString(name),
+ modified_type->GetByteSize(), nullptr,
+ LLDB_INVALID_UID, Type::eEncodingIsUID, decl,
+ ct, Type::eResolveStateFull);
+}
+
+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 std::make_shared<Type>(toOpaqueUid(type_id), this, ConstString(),
+ pr.getSize(), nullptr, LLDB_INVALID_UID,
+ Type::eEncodingIsUID, decl, ct,
+ Type::eResolveStateFull);
+}
+
+lldb::TypeSP SymbolFileNativePDB::CreateSimpleType(TypeIndex ti,
+ CompilerType ct) {
+ uint64_t uid = toOpaqueUid(PdbTypeSymId(ti, false));
+ if (ti == TypeIndex::NullptrT()) {
+ Declaration decl;
+ return std::make_shared<Type>(
+ uid, this, ConstString("std::nullptr_t"), 0, nullptr, LLDB_INVALID_UID,
+ Type::eEncodingIsUID, decl, ct, Type::eResolveStateFull);
+ }
+
+ 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 std::make_shared<Type>(
+ uid, this, ConstString(), pointer_size, nullptr, LLDB_INVALID_UID,
+ Type::eEncodingIsUID, decl, ct, Type::eResolveStateFull);
+ }
+
+ if (ti.getSimpleKind() == SimpleTypeKind::NotTranslated)
+ return nullptr;
+
+ size_t size = GetTypeSizeForSimpleKind(ti.getSimpleKind());
+ llvm::StringRef type_name = GetSimpleTypeName(ti.getSimpleKind());
+
+ Declaration decl;
+ return std::make_shared<Type>(uid, this, ConstString(type_name), size,
+ nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID,
+ decl, ct, Type::eResolveStateFull);
+}
+
+static std::string GetUnqualifiedTypeName(const TagRecord &record) {
+ if (!record.hasUniqueName()) {
+ MSVCUndecoratedNameParser parser(record.Name);
+ llvm::ArrayRef<MSVCUndecoratedNameSpecifier> specs = parser.GetSpecifiers();
+
+ return specs.back().GetBaseName();
+ }
+
+ llvm::ms_demangle::Demangler demangler;
+ StringView sv(record.UniqueName.begin(), record.UniqueName.size());
+ llvm::ms_demangle::TagTypeNode *ttn = demangler.parseTagUniqueName(sv);
+ if (demangler.Error)
+ return 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 std::make_shared<Type>(toOpaqueUid(type_id), this, ConstString(uname),
+ size, nullptr, LLDB_INVALID_UID,
+ Type::eEncodingIsUID, decl, ct,
+ Type::eResolveStateForward);
+}
+
+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 std::make_shared<lldb_private::Type>(
+ toOpaqueUid(type_id), this, ConstString(uname),
+ underlying_type->GetByteSize(), nullptr, LLDB_INVALID_UID,
+ lldb_private::Type::eEncodingIsUID, decl, ct,
+ lldb_private::Type::eResolveStateForward);
+}
+
+TypeSP SymbolFileNativePDB::CreateArrayType(PdbTypeSymId type_id,
+ const ArrayRecord &ar,
+ CompilerType ct) {
+ TypeSP element_type = GetOrCreateType(ar.ElementType);
+
+ Declaration decl;
+ TypeSP array_sp = std::make_shared<lldb_private::Type>(
+ toOpaqueUid(type_id), this, ConstString(), ar.Size, nullptr,
+ LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, ct,
+ lldb_private::Type::eResolveStateFull);
+ array_sp->SetEncodingType(element_type.get());
+ return array_sp;
+}
+
+TypeSP SymbolFileNativePDB::CreateProcedureType(PdbTypeSymId type_id,
+ const ProcedureRecord &pr,
+ CompilerType ct) {
+ Declaration decl;
+ return std::make_shared<lldb_private::Type>(
+ toOpaqueUid(type_id), this, ConstString(), 0, nullptr, LLDB_INVALID_UID,
+ lldb_private::Type::eEncodingIsUID, decl, ct,
+ lldb_private::Type::eResolveStateFull);
+}
+
+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);
+ }
+
+ 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.
+ llvm::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;
+
+ clang::QualType qt = m_ast->GetOrCreateType(best_decl_id);
+
+ TypeSP result = CreateType(best_decl_id, m_ast->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)
+ m_obj_file->GetModule()->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;
+ LLVM_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;
+ LLVM_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;
+ llvm::Optional<uint16_t> modi = m_index->GetModuleIndexForVa(addr);
+ if (modi) {
+ 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;
+
+ m_ast->GetOrCreateVariableDecl(var_id);
+
+ DWARFExpression location = MakeGlobalLocationExpression(
+ section, offset, GetObjectFile()->GetModule());
+
+ std::string global_name("::");
+ global_name += name;
+ 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, false,
+ false);
+ var_sp->SetLocationIsConstantValueData(false);
+
+ 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();
+ DWARFExpression location = MakeConstantLocationExpression(
+ constant.Type, tpi, constant.Value, module);
+
+ 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,
+ false, false, false);
+ var_sp->SetLocationIsConstantValueData(true);
+ 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)
+ emplace_result.first->second = CreateGlobalVariable(var_id);
+
+ 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) {
+ clang::DeclContext *context = m_ast->FromCompilerDeclContext(decl_ctx);
+ if (!context)
+ return;
+ m_ast->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) {
+ 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) { return; }
+
+size_t SymbolFileNativePDB::ParseFunctions(CompileUnit &comp_unit) {
+ 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) {
+ uint32_t resolved_flags = 0;
+ lldb::addr_t file_addr = addr.GetFileAddress();
+
+ if (NeedsResolvedCompileUnit(resolve_scope)) {
+ llvm::Optional<uint16_t> modi = m_index->GetModuleIndexForVa(file_addr);
+ if (!modi)
+ return 0;
+ CompilandIndexItem *cci = m_index->compilands().GetCompiland(*modi);
+ if (!cci)
+ return 0;
+
+ sc.comp_unit = GetOrCreateCompileUnit(*cci).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();
+ sc.block = sc.GetFunctionBlock();
+ }
+
+ if (type == PDB_SymType::Block) {
+ sc.block = &GetOrCreateBlock(csid);
+ sc.function = sc.block->CalculateSymbolContextFunction();
+ }
+ resolved_flags |= eSymbolContextFunction;
+ 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 FileSpec &file_spec, uint32_t line, bool check_inlines,
+ lldb::SymbolContextItem resolve_scope, SymbolContextList &sc_list) {
+ return 0;
+}
+
+static void AppendLineEntryToSequence(LineTable &table, LineSequence &sequence,
+ const CompilandIndexItem &cci,
+ lldb::addr_t base_addr,
+ uint32_t file_number,
+ const LineFragmentHeader &block,
+ const LineNumberEntry &cur) {
+ LineInfo cur_info(cur.Flags);
+
+ if (cur_info.isAlwaysStepInto() || cur_info.isNeverStepInto())
+ return;
+
+ uint64_t addr = base_addr + cur.Offset;
+
+ bool is_statement = cur_info.isStatement();
+ bool is_prologue = IsFunctionPrologue(cci, addr);
+ bool is_epilogue = IsFunctionEpilogue(cci, addr);
+
+ uint32_t lno = cur_info.getStartLine();
+
+ table.AppendLineEntryToSequence(&sequence, addr, lno, 0, file_number,
+ is_statement, false, is_prologue, is_epilogue,
+ false);
+}
+
+static void TerminateLineSequence(LineTable &table,
+ const LineFragmentHeader &block,
+ lldb::addr_t base_addr, uint32_t file_number,
+ uint32_t last_line,
+ std::unique_ptr<LineSequence> seq) {
+ // The end is always a terminal entry, so insert it regardless.
+ table.AppendLineEntryToSequence(seq.get(), base_addr + block.CodeSize,
+ last_line, 0, file_number, false, false,
+ false, false, true);
+ table.InsertSequence(seq.release());
+}
+
+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.
+ PdbSymUid cu_id(comp_unit.GetID());
+ lldbassert(cu_id.kind() == PdbSymUidKind::Compiland);
+ CompilandIndexItem *cci =
+ m_index->compilands().GetCompiland(cu_id.asCompiland().modi);
+ lldbassert(cci);
+ auto line_table = llvm::make_unique<LineTable>(&comp_unit);
+
+ // 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 :
+ cci->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);
+
+ const auto &checksums = cci->m_strings.checksums().getArray();
+ const auto &strings = cci->m_strings.strings();
+ for (const LineColumnEntry &group : lines) {
+ // 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(group.NameIndex);
+ if (iter == checksums.end())
+ continue;
+
+ llvm::Expected<llvm::StringRef> efn =
+ strings.getString(iter->FileNameOffset);
+ if (!efn) {
+ llvm::consumeError(efn.takeError());
+ continue;
+ }
+
+ // LLDB wants the index of the file in the list of support files.
+ auto fn_iter = llvm::find(cci->m_file_list, *efn);
+ lldbassert(fn_iter != cci->m_file_list.end());
+ // LLDB support file indices are 1-based.
+ uint32_t file_index =
+ 1 + std::distance(cci->m_file_list.begin(), fn_iter);
+
+ std::unique_ptr<LineSequence> sequence(
+ line_table->CreateLineSequenceContainer());
+ lldbassert(!group.LineNumbers.empty());
+
+ for (const LineNumberEntry &entry : group.LineNumbers) {
+ AppendLineEntryToSequence(*line_table, *sequence, *cci, virtual_addr,
+ file_index, *lfh, entry);
+ }
+ LineInfo last_line(group.LineNumbers.back().Flags);
+ TerminateLineSequence(*line_table, *lfh, virtual_addr, file_index,
+ last_line.getEndLine(), std::move(sequence));
+ }
+ }
+
+ 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;
+}
+
+bool SymbolFileNativePDB::ParseSupportFiles(CompileUnit &comp_unit,
+ FileSpecList &support_files) {
+ 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.startswith("/") ? FileSpec::Style::posix : FileSpec::Style::windows;
+ FileSpec spec(f, style);
+ support_files.Append(spec);
+ }
+
+ llvm::SmallString<64> main_source_file =
+ m_index->compilands().GetMainSourceFile(*cci);
+ FileSpec::Style style = main_source_file.startswith("/")
+ ? FileSpec::Style::posix
+ : FileSpec::Style::windows;
+ FileSpec spec(main_source_file, style);
+ support_files.Insert(0, spec);
+ return true;
+}
+
+bool SymbolFileNativePDB::ParseImportedModules(
+ const SymbolContext &sc, std::vector<ConstString> &imported_modules) {
+ // PDB does not yet support module debug info
+ return false;
+}
+
+size_t SymbolFileNativePDB::ParseBlocksRecursive(Function &func) {
+ GetOrCreateBlock(PdbSymUid(func.GetID()).asCompilandSym());
+ // FIXME: Parse child blocks
+ return 1;
+}
+
+void SymbolFileNativePDB::DumpClangAST(Stream &s) { m_ast->Dump(s); }
+
+uint32_t SymbolFileNativePDB::FindGlobalVariables(
+ const ConstString &name, const CompilerDeclContext *parent_decl_ctx,
+ uint32_t max_matches, VariableList &variables) {
+ 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) {
+ VariableSP var;
+ 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);
+ var = GetOrCreateGlobalVariable(global);
+ variables.AddVariable(var);
+ break;
+ }
+ default:
+ continue;
+ }
+ }
+ return variables.GetSize();
+}
+
+uint32_t SymbolFileNativePDB::FindFunctions(
+ const ConstString &name, const CompilerDeclContext *parent_decl_ctx,
+ FunctionNameType name_type_mask, bool include_inlines, bool append,
+ SymbolContextList &sc_list) {
+ // For now we only support lookup by method name.
+ if (!(name_type_mask & eFunctionNameTypeMethod))
+ return 0;
+
+ 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);
+ }
+
+ return sc_list.GetSize();
+}
+
+uint32_t SymbolFileNativePDB::FindFunctions(const RegularExpression &regex,
+ bool include_inlines, bool append,
+ SymbolContextList &sc_list) {
+ return 0;
+}
+
+uint32_t SymbolFileNativePDB::FindTypes(
+ const ConstString &name, const CompilerDeclContext *parent_decl_ctx,
+ bool append, uint32_t max_matches,
+ llvm::DenseSet<SymbolFile *> &searched_symbol_files, TypeMap &types) {
+ if (!append)
+ types.Clear();
+ if (!name)
+ return 0;
+
+ searched_symbol_files.clear();
+ searched_symbol_files.insert(this);
+
+ // There is an assumption 'name' is not a regex
+ size_t match_count = FindTypesByName(name.GetStringRef(), max_matches, types);
+
+ return match_count;
+}
+
+size_t
+SymbolFileNativePDB::FindTypes(const std::vector<CompilerContext> &context,
+ bool append, TypeMap &types) {
+ return 0;
+}
+
+size_t SymbolFileNativePDB::FindTypesByName(llvm::StringRef name,
+ uint32_t max_matches,
+ TypeMap &types) {
+
+ size_t match_count = 0;
+ 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);
+ ++match_count;
+ }
+ return match_count;
+}
+
+size_t SymbolFileNativePDB::ParseTypes(CompileUnit &comp_unit) {
+ // Only do the full type scan the first time.
+ if (m_done_full_type_scan)
+ return 0;
+
+ size_t old_count = m_obj_file->GetModule()->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);
+ }
+
+ size_t new_count = m_obj_file->GetModule()->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();
+ VariableInfo var_info = GetVariableLocationInfo(*m_index, var_id, module);
+ if (!var_info.location || !var_info.ranges)
+ return nullptr;
+
+ CompilandIndexItem *cii = m_index->compilands().GetCompiland(var_id.modi);
+ CompUnitSP comp_unit_sp = GetOrCreateCompileUnit(*cii);
+ TypeSP type_sp = GetOrCreateType(var_info.type);
+ std::string name = var_info.name.str();
+ Declaration decl;
+ SymbolFileTypeSP sftype =
+ std::make_shared<SymbolFileType>(*this, type_sp->GetID());
+
+ ValueType var_scope =
+ is_param ? eValueTypeVariableArgument : eValueTypeVariableLocal;
+ VariableSP var_sp = std::make_shared<Variable>(
+ toOpaqueUid(var_id), name.c_str(), name.c_str(), sftype, var_scope,
+ comp_unit_sp.get(), *var_info.ranges, &decl, *var_info.location, false,
+ false, false);
+
+ if (!is_param)
+ m_ast->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);
+
+ (void)m_ast->GetOrCreateTypedefDecl(id);
+
+ Declaration decl;
+ return std::make_shared<lldb_private::Type>(
+ toOpaqueUid(id), this, ConstString(udt.Name), target_type->GetByteSize(),
+ nullptr, target_type->GetID(), lldb_private::Type::eEncodingIsTypedefUID,
+ decl, target_type->GetForwardCompilerType(),
+ lldb_private::Type::eResolveStateForward);
+}
+
+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);
+ ProcedureRecord sig;
+ cantFail(TypeDeserializer::deserializeAs<ProcedureRecord>(signature, sig));
+ params_remaining = sig.getParameterCount();
+ break;
+ }
+ case S_BLOCK32:
+ 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, recurse into its children and then skip it.
+ if (variable_cvs.kind() == S_BLOCK32) {
+ 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) {
+ 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) {
+ clang::Decl *decl = m_ast->GetOrCreateDeclForUid(PdbSymUid(uid));
+
+ return m_ast->ToCompilerDecl(*decl);
+}
+
+CompilerDeclContext
+SymbolFileNativePDB::GetDeclContextForUID(lldb::user_id_t uid) {
+ clang::DeclContext *context =
+ m_ast->GetOrCreateDeclContextForUid(PdbSymUid(uid));
+ if (!context)
+ return {};
+
+ return m_ast->ToCompilerDeclContext(*context);
+}
+
+CompilerDeclContext
+SymbolFileNativePDB::GetDeclContextContainingUID(lldb::user_id_t uid) {
+ clang::DeclContext *context = m_ast->GetParentDeclContext(PdbSymUid(uid));
+ return m_ast->ToCompilerDeclContext(*context);
+}
+
+Type *SymbolFileNativePDB::ResolveTypeUID(lldb::user_id_t type_uid) {
+ 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);
+ return &*type_sp;
+}
+
+llvm::Optional<SymbolFile::ArrayInfo>
+SymbolFileNativePDB::GetDynamicArrayInfoForUID(
+ lldb::user_id_t type_uid, const lldb_private::ExecutionContext *exe_ctx) {
+ return llvm::None;
+}
+
+
+bool SymbolFileNativePDB::CompleteType(CompilerType &compiler_type) {
+ clang::QualType qt =
+ clang::QualType::getFromOpaquePtr(compiler_type.GetOpaqueQualType());
+
+ return m_ast->CompleteType(qt);
+}
+
+size_t SymbolFileNativePDB::GetTypes(lldb_private::SymbolContextScope *sc_scope,
+ TypeClass type_mask,
+ lldb_private::TypeList &type_list) {
+ return 0;
+}
+
+CompilerDeclContext
+SymbolFileNativePDB::FindNamespace(const ConstString &name,
+ const CompilerDeclContext *parent_decl_ctx) {
+ return {};
+}
+
+TypeSystem *
+SymbolFileNativePDB::GetTypeSystemForLanguage(lldb::LanguageType language) {
+ auto type_system =
+ m_obj_file->GetModule()->GetTypeSystemForLanguage(language);
+ if (type_system)
+ type_system->SetSymbolFile(this);
+ return type_system;
+}
+
+ConstString SymbolFileNativePDB::GetPluginName() {
+ static ConstString g_name("pdb");
+ return g_name;
+}
+
+uint32_t SymbolFileNativePDB::GetPluginVersion() { return 1; }
diff --git a/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h b/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
new file mode 100644
index 000000000000..dcf3fe365ef1
--- /dev/null
+++ b/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
@@ -0,0 +1,245 @@
+//===-- SymbolFileNativePDB.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_SYMBOLFILENATIVEPDB_H
+#define LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_SYMBOLFILENATIVEPDB_H
+
+#include "lldb/Symbol/ClangASTImporter.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"
+
+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 {
+class ClangASTImporter;
+
+namespace npdb {
+class PdbAstBuilder;
+
+class SymbolFileNativePDB : public SymbolFile {
+ friend class UdtRecordCompleter;
+
+public:
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void Initialize();
+
+ static void Terminate();
+
+ static void DebuggerInitialize(Debugger &debugger);
+
+ static ConstString GetPluginNameStatic();
+
+ static const char *GetPluginDescriptionStatic();
+
+ static SymbolFile *CreateInstance(ObjectFile *obj_file);
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ SymbolFileNativePDB(ObjectFile *ofile);
+
+ ~SymbolFileNativePDB() override;
+
+ uint32_t CalculateAbilities() override;
+
+ void InitializeObject() override;
+
+ //------------------------------------------------------------------
+ // Compile Unit function calls
+ //------------------------------------------------------------------
+
+ uint32_t GetNumCompileUnits() override;
+
+ void
+ ParseDeclsForContext(lldb_private::CompilerDeclContext decl_ctx) override;
+
+ lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index) 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,
+ FileSpecList &support_files) override;
+ size_t ParseTypes(lldb_private::CompileUnit &comp_unit) override;
+
+ bool
+ ParseImportedModules(const SymbolContext &sc,
+ std::vector<ConstString> &imported_modules) override;
+
+ size_t ParseBlocksRecursive(Function &func) override;
+
+ uint32_t FindGlobalVariables(const 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;
+ llvm::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 FileSpec &file_spec, uint32_t line,
+ bool check_inlines,
+ lldb::SymbolContextItem resolve_scope,
+ SymbolContextList &sc_list) override;
+
+ size_t GetTypes(SymbolContextScope *sc_scope, lldb::TypeClass type_mask,
+ TypeList &type_list) override;
+
+ uint32_t FindFunctions(const ConstString &name,
+ const CompilerDeclContext *parent_decl_ctx,
+ lldb::FunctionNameType name_type_mask,
+ bool include_inlines, bool append,
+ SymbolContextList &sc_list) override;
+
+ uint32_t FindFunctions(const RegularExpression &regex, bool include_inlines,
+ bool append, SymbolContextList &sc_list) override;
+
+ uint32_t FindTypes(const ConstString &name,
+ const CompilerDeclContext *parent_decl_ctx, bool append,
+ uint32_t max_matches,
+ llvm::DenseSet<SymbolFile *> &searched_symbol_files,
+ TypeMap &types) override;
+
+ size_t FindTypes(const std::vector<CompilerContext> &context, bool append,
+ TypeMap &types) override;
+
+ TypeSystem *GetTypeSystemForLanguage(lldb::LanguageType language) override;
+
+ CompilerDeclContext
+ FindNamespace(const ConstString &name,
+ const CompilerDeclContext *parent_decl_ctx) override;
+
+ ConstString GetPluginName() override;
+
+ uint32_t GetPluginVersion() override;
+
+ llvm::pdb::PDBFile &GetPDBFile() { return m_index->pdb(); }
+ const llvm::pdb::PDBFile &GetPDBFile() const { return m_index->pdb(); }
+
+ void DumpClangAST(Stream &s) override;
+
+private:
+
+ size_t 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 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::BumpPtrAllocator m_allocator;
+
+ lldb::addr_t m_obj_load_address = 0;
+ bool m_done_full_type_scan = false;
+
+ std::unique_ptr<PdbIndex> m_index;
+
+ std::unique_ptr<PdbAstBuilder> m_ast;
+
+ 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;
+};
+
+} // namespace npdb
+} // namespace lldb_private
+
+#endif // lldb_Plugins_SymbolFile_PDB_SymbolFilePDB_h_
diff --git a/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp b/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
new file mode 100644
index 000000000000..239dfbee625d
--- /dev/null
+++ b/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
@@ -0,0 +1,191 @@
+#include "UdtRecordCompleter.h"
+
+#include "PdbAstBuilder.h"
+#include "PdbIndex.h"
+#include "PdbSymUid.h"
+#include "PdbUtil.h"
+
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/ClangASTImporter.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/DebugInfo/PDB/PDBTypes.h"
+
+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,
+ TpiStream &tpi)
+ : m_id(id), m_derived_ct(derived_ct), m_tag_decl(tag_decl),
+ m_ast_builder(ast_builder), m_tpi(tpi) {
+ CVType cvt = m_tpi.getType(m_id.index);
+ switch (cvt.kind()) {
+ case LF_ENUM:
+ llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, m_cvr.er));
+ break;
+ case LF_UNION:
+ llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, m_cvr.ur));
+ break;
+ case LF_CLASS:
+ case LF_STRUCTURE:
+ llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, m_cvr.cr));
+ break;
+ default:
+ llvm_unreachable("unreachable!");
+ }
+}
+
+clang::QualType UdtRecordCompleter::AddBaseClassForTypeIndex(
+ llvm::codeview::TypeIndex ti, llvm::codeview::MemberAccess access) {
+ PdbTypeSymId type_id(ti);
+ clang::QualType qt = m_ast_builder.GetOrCreateType(type_id);
+
+ CVType udt_cvt = m_tpi.getType(ti);
+
+ std::unique_ptr<clang::CXXBaseSpecifier> base_spec =
+ m_ast_builder.clang().CreateBaseClassSpecifier(
+ qt.getAsOpaquePtr(), TranslateMemberAccess(access), false,
+ udt_cvt.kind() == LF_CLASS);
+ lldbassert(base_spec);
+ m_bases.push_back(std::move(base_spec));
+ return qt;
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+ BaseClassRecord &base) {
+ clang::QualType base_qt =
+ AddBaseClassForTypeIndex(base.Type, base.getAccess());
+
+ 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());
+
+ // FIXME: Handle virtual base offsets.
+ 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));
+
+ m_ast_builder.CompleteType(member_type);
+
+ CompilerType member_ct = m_ast_builder.ToCompilerType(member_type);
+
+ lldb::AccessType access =
+ TranslateMemberAccess(static_data_member.getAccess());
+ ClangASTContext::AddVariableToRecordType(
+ m_derived_ct, static_data_member.Name, member_ct, access);
+
+ // 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_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));
+ m_ast_builder.CompleteType(member_qt);
+
+ lldb::AccessType access = TranslateMemberAccess(data_member.getAccess());
+
+ clang::FieldDecl *decl = ClangASTContext::AddFieldToRecordType(
+ m_derived_ct, data_member.Name, m_ast_builder.ToCompilerType(member_qt),
+ access, bitfield_width);
+ // FIXME: Add a PdbSymUid namespace for field list members and update
+ // the m_uid_to_decl map with this decl.
+
+ m_layout.field_offsets.insert(std::make_pair(decl, offset));
+
+ return Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+ OneMethodRecord &one_method) {
+ return Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+ OverloadedMethodRecord &overloaded) {
+ 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() {
+ ClangASTContext &clang = m_ast_builder.clang();
+ clang.TransferBaseClasses(m_derived_ct.GetOpaqueQualType(),
+ std::move(m_bases));
+
+ clang.AddMethodOverridesForCXXRecordType(m_derived_ct.GetOpaqueQualType());
+ ClangASTContext::BuildIndirectFields(m_derived_ct);
+ ClangASTContext::CompleteTagDeclarationDefinition(m_derived_ct);
+
+ if (auto *record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(&m_tag_decl)) {
+ m_ast_builder.importer().InsertRecordDecl(record_decl, m_layout);
+ }
+}
diff --git a/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h b/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h
new file mode 100644
index 000000000000..469685126e59
--- /dev/null
+++ b/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h
@@ -0,0 +1,75 @@
+//===-- SymbolFileNativePDB.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_UDTRECORDCOMPLETER_H
+#define LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_UDTRECORDCOMPLETER_H
+
+#include "lldb/Symbol/ClangASTImporter.h"
+#include "llvm/DebugInfo/CodeView/CVRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
+
+#include "PdbSymUid.h"
+
+namespace clang {
+class CXXBaseSpecifier;
+class QualType;
+class TagDecl;
+} // namespace clang
+
+namespace llvm {
+namespace pdb {
+class TpiStream;
+}
+} // namespace llvm
+
+namespace lldb_private {
+class Type;
+class CompilerType;
+namespace npdb {
+class PdbAstBuilder;
+
+class UdtRecordCompleter : public llvm::codeview::TypeVisitorCallbacks {
+ 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;
+ llvm::pdb::TpiStream &m_tpi;
+ std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> m_bases;
+ ClangASTImporter::LayoutInfo m_layout;
+
+public:
+ UdtRecordCompleter(PdbTypeSymId id, CompilerType &derived_ct,
+ clang::TagDecl &tag_decl, PdbAstBuilder &ast_builder,
+ llvm::pdb::TpiStream &tpi);
+
+#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"
+
+ void complete();
+
+private:
+ clang::QualType AddBaseClassForTypeIndex(llvm::codeview::TypeIndex ti,
+ llvm::codeview::MemberAccess access);
+};
+
+} // namespace npdb
+} // namespace lldb_private
+
+#endif // LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_UDTRECORDCOMPLETER_H