Path: blob/main/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
39644 views
//===-- SymbolFileNativePDB.cpp -------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "SymbolFileNativePDB.h"910#include "Plugins/ExpressionParser/Clang/ClangUtil.h"11#include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h"12#include "Plugins/ObjectFile/PDB/ObjectFilePDB.h"13#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"14#include "lldb/Core/Module.h"15#include "lldb/Core/PluginManager.h"16#include "lldb/Symbol/CompileUnit.h"17#include "lldb/Symbol/LineTable.h"18#include "lldb/Symbol/ObjectFile.h"19#include "lldb/Symbol/SymbolContext.h"20#include "lldb/Symbol/SymbolVendor.h"21#include "lldb/Symbol/Variable.h"22#include "lldb/Symbol/VariableList.h"23#include "lldb/Utility/LLDBLog.h"24#include "lldb/Utility/Log.h"2526#include "llvm/DebugInfo/CodeView/CVRecord.h"27#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"28#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"29#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"30#include "llvm/DebugInfo/CodeView/RecordName.h"31#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"32#include "llvm/DebugInfo/CodeView/SymbolRecordHelpers.h"33#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"34#include "llvm/DebugInfo/PDB/Native/DbiStream.h"35#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"36#include "llvm/DebugInfo/PDB/Native/InfoStream.h"37#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"38#include "llvm/DebugInfo/PDB/Native/NativeSession.h"39#include "llvm/DebugInfo/PDB/Native/PDBFile.h"40#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"41#include "llvm/DebugInfo/PDB/Native/TpiStream.h"42#include "llvm/DebugInfo/PDB/PDB.h"43#include "llvm/DebugInfo/PDB/PDBTypes.h"44#include "llvm/Demangle/MicrosoftDemangle.h"45#include "llvm/Object/COFF.h"46#include "llvm/Support/Allocator.h"47#include "llvm/Support/BinaryStreamReader.h"48#include "llvm/Support/Error.h"49#include "llvm/Support/ErrorOr.h"50#include "llvm/Support/MemoryBuffer.h"5152#include "DWARFLocationExpression.h"53#include "PdbSymUid.h"54#include "PdbUtil.h"55#include "UdtRecordCompleter.h"56#include <optional>57#include <string_view>5859using namespace lldb;60using namespace lldb_private;61using namespace npdb;62using namespace llvm::codeview;63using namespace llvm::pdb;6465char SymbolFileNativePDB::ID;6667static lldb::LanguageType TranslateLanguage(PDB_Lang lang) {68switch (lang) {69case PDB_Lang::Cpp:70return lldb::LanguageType::eLanguageTypeC_plus_plus;71case PDB_Lang::C:72return lldb::LanguageType::eLanguageTypeC;73case PDB_Lang::Swift:74return lldb::LanguageType::eLanguageTypeSwift;75case PDB_Lang::Rust:76return lldb::LanguageType::eLanguageTypeRust;77case PDB_Lang::ObjC:78return lldb::LanguageType::eLanguageTypeObjC;79case PDB_Lang::ObjCpp:80return lldb::LanguageType::eLanguageTypeObjC_plus_plus;81default:82return lldb::LanguageType::eLanguageTypeUnknown;83}84}8586static std::unique_ptr<PDBFile>87loadMatchingPDBFile(std::string exe_path, llvm::BumpPtrAllocator &allocator) {88// Try to find a matching PDB for an EXE.89using namespace llvm::object;90auto expected_binary = createBinary(exe_path);9192// If the file isn't a PE/COFF executable, fail.93if (!expected_binary) {94llvm::consumeError(expected_binary.takeError());95return nullptr;96}97OwningBinary<Binary> binary = std::move(*expected_binary);9899// TODO: Avoid opening the PE/COFF binary twice by reading this information100// directly from the lldb_private::ObjectFile.101auto *obj = llvm::dyn_cast<llvm::object::COFFObjectFile>(binary.getBinary());102if (!obj)103return nullptr;104const llvm::codeview::DebugInfo *pdb_info = nullptr;105106// If it doesn't have a debug directory, fail.107llvm::StringRef pdb_file;108if (llvm::Error e = obj->getDebugPDBInfo(pdb_info, pdb_file)) {109consumeError(std::move(e));110return nullptr;111}112113// If the file doesn't exist, perhaps the path specified at build time114// doesn't match the PDB's current location, so check the location of the115// executable.116if (!FileSystem::Instance().Exists(pdb_file)) {117const auto exe_dir = FileSpec(exe_path).CopyByRemovingLastPathComponent();118const auto pdb_name = FileSpec(pdb_file).GetFilename().GetCString();119pdb_file = exe_dir.CopyByAppendingPathComponent(pdb_name).GetPathAsConstString().GetStringRef();120}121122// If the file is not a PDB or if it doesn't have a matching GUID, fail.123auto pdb = ObjectFilePDB::loadPDBFile(std::string(pdb_file), allocator);124if (!pdb)125return nullptr;126127auto expected_info = pdb->getPDBInfoStream();128if (!expected_info) {129llvm::consumeError(expected_info.takeError());130return nullptr;131}132llvm::codeview::GUID guid;133memcpy(&guid, pdb_info->PDB70.Signature, 16);134135if (expected_info->getGuid() != guid)136return nullptr;137return pdb;138}139140static bool IsFunctionPrologue(const CompilandIndexItem &cci,141lldb::addr_t addr) {142// FIXME: Implement this.143return false;144}145146static bool IsFunctionEpilogue(const CompilandIndexItem &cci,147lldb::addr_t addr) {148// FIXME: Implement this.149return false;150}151152static llvm::StringRef GetSimpleTypeName(SimpleTypeKind kind) {153switch (kind) {154case SimpleTypeKind::Boolean128:155case SimpleTypeKind::Boolean16:156case SimpleTypeKind::Boolean32:157case SimpleTypeKind::Boolean64:158case SimpleTypeKind::Boolean8:159return "bool";160case SimpleTypeKind::Byte:161case SimpleTypeKind::UnsignedCharacter:162return "unsigned char";163case SimpleTypeKind::NarrowCharacter:164return "char";165case SimpleTypeKind::SignedCharacter:166case SimpleTypeKind::SByte:167return "signed char";168case SimpleTypeKind::Character16:169return "char16_t";170case SimpleTypeKind::Character32:171return "char32_t";172case SimpleTypeKind::Character8:173return "char8_t";174case SimpleTypeKind::Complex80:175case SimpleTypeKind::Complex64:176case SimpleTypeKind::Complex32:177return "complex";178case SimpleTypeKind::Float128:179case SimpleTypeKind::Float80:180return "long double";181case SimpleTypeKind::Float64:182return "double";183case SimpleTypeKind::Float32:184return "float";185case SimpleTypeKind::Float16:186return "single";187case SimpleTypeKind::Int128:188return "__int128";189case SimpleTypeKind::Int64:190case SimpleTypeKind::Int64Quad:191return "int64_t";192case SimpleTypeKind::Int32:193return "int";194case SimpleTypeKind::Int16:195return "short";196case SimpleTypeKind::UInt128:197return "unsigned __int128";198case SimpleTypeKind::UInt64:199case SimpleTypeKind::UInt64Quad:200return "uint64_t";201case SimpleTypeKind::HResult:202return "HRESULT";203case SimpleTypeKind::UInt32:204return "unsigned";205case SimpleTypeKind::UInt16:206case SimpleTypeKind::UInt16Short:207return "unsigned short";208case SimpleTypeKind::Int32Long:209return "long";210case SimpleTypeKind::UInt32Long:211return "unsigned long";212case SimpleTypeKind::Void:213return "void";214case SimpleTypeKind::WideCharacter:215return "wchar_t";216default:217return "";218}219}220221static bool IsClassRecord(TypeLeafKind kind) {222switch (kind) {223case LF_STRUCTURE:224case LF_CLASS:225case LF_INTERFACE:226return true;227default:228return false;229}230}231232static std::optional<CVTagRecord>233GetNestedTagDefinition(const NestedTypeRecord &Record,234const CVTagRecord &parent, TpiStream &tpi) {235// An LF_NESTTYPE is essentially a nested typedef / using declaration, but it236// is also used to indicate the primary definition of a nested class. That is237// to say, if you have:238// struct A {239// struct B {};240// using C = B;241// };242// Then in the debug info, this will appear as:243// LF_STRUCTURE `A::B` [type index = N]244// LF_STRUCTURE `A`245// LF_NESTTYPE [name = `B`, index = N]246// LF_NESTTYPE [name = `C`, index = N]247// In order to accurately reconstruct the decl context hierarchy, we need to248// know which ones are actual definitions and which ones are just aliases.249250// If it's a simple type, then this is something like `using foo = int`.251if (Record.Type.isSimple())252return std::nullopt;253254CVType cvt = tpi.getType(Record.Type);255256if (!IsTagRecord(cvt))257return std::nullopt;258259// If it's an inner definition, then treat whatever name we have here as a260// single component of a mangled name. So we can inject it into the parent's261// mangled name to see if it matches.262CVTagRecord child = CVTagRecord::create(cvt);263std::string qname = std::string(parent.asTag().getUniqueName());264if (qname.size() < 4 || child.asTag().getUniqueName().size() < 4)265return std::nullopt;266267// qname[3] is the tag type identifier (struct, class, union, etc). Since the268// inner tag type is not necessarily the same as the outer tag type, re-write269// it to match the inner tag type.270qname[3] = child.asTag().getUniqueName()[3];271std::string piece;272if (qname[3] == 'W')273piece = "4";274piece += Record.Name;275piece.push_back('@');276qname.insert(4, std::move(piece));277if (qname != child.asTag().UniqueName)278return std::nullopt;279280return std::move(child);281}282283void SymbolFileNativePDB::Initialize() {284PluginManager::RegisterPlugin(GetPluginNameStatic(),285GetPluginDescriptionStatic(), CreateInstance,286DebuggerInitialize);287}288289void SymbolFileNativePDB::Terminate() {290PluginManager::UnregisterPlugin(CreateInstance);291}292293void SymbolFileNativePDB::DebuggerInitialize(Debugger &debugger) {}294295llvm::StringRef SymbolFileNativePDB::GetPluginDescriptionStatic() {296return "Microsoft PDB debug symbol cross-platform file reader.";297}298299SymbolFile *SymbolFileNativePDB::CreateInstance(ObjectFileSP objfile_sp) {300return new SymbolFileNativePDB(std::move(objfile_sp));301}302303SymbolFileNativePDB::SymbolFileNativePDB(ObjectFileSP objfile_sp)304: SymbolFileCommon(std::move(objfile_sp)) {}305306SymbolFileNativePDB::~SymbolFileNativePDB() = default;307308uint32_t SymbolFileNativePDB::CalculateAbilities() {309uint32_t abilities = 0;310if (!m_objfile_sp)311return 0;312313if (!m_index) {314// Lazily load and match the PDB file, but only do this once.315PDBFile *pdb_file;316if (auto *pdb = llvm::dyn_cast<ObjectFilePDB>(m_objfile_sp.get())) {317pdb_file = &pdb->GetPDBFile();318} else {319m_file_up = loadMatchingPDBFile(m_objfile_sp->GetFileSpec().GetPath(),320m_allocator);321pdb_file = m_file_up.get();322}323324if (!pdb_file)325return 0;326327auto expected_index = PdbIndex::create(pdb_file);328if (!expected_index) {329llvm::consumeError(expected_index.takeError());330return 0;331}332m_index = std::move(*expected_index);333}334if (!m_index)335return 0;336337// We don't especially have to be precise here. We only distinguish between338// stripped and not stripped.339abilities = kAllAbilities;340341if (m_index->dbi().isStripped())342abilities &= ~(Blocks | LocalVariables);343return abilities;344}345346void SymbolFileNativePDB::InitializeObject() {347m_obj_load_address = m_objfile_sp->GetModule()348->GetObjectFile()349->GetBaseAddress()350.GetFileAddress();351m_index->SetLoadAddress(m_obj_load_address);352m_index->ParseSectionContribs();353354auto ts_or_err = m_objfile_sp->GetModule()->GetTypeSystemForLanguage(355lldb::eLanguageTypeC_plus_plus);356if (auto err = ts_or_err.takeError()) {357LLDB_LOG_ERROR(GetLog(LLDBLog::Symbols), std::move(err),358"Failed to initialize: {0}");359} else {360if (auto ts = *ts_or_err)361ts->SetSymbolFile(this);362BuildParentMap();363}364}365366uint32_t SymbolFileNativePDB::CalculateNumCompileUnits() {367const DbiModuleList &modules = m_index->dbi().modules();368uint32_t count = modules.getModuleCount();369if (count == 0)370return count;371372// The linker can inject an additional "dummy" compilation unit into the373// PDB. Ignore this special compile unit for our purposes, if it is there.374// It is always the last one.375DbiModuleDescriptor last = modules.getModuleDescriptor(count - 1);376if (last.getModuleName() == "* Linker *")377--count;378return count;379}380381Block &SymbolFileNativePDB::CreateBlock(PdbCompilandSymId block_id) {382CompilandIndexItem *cii = m_index->compilands().GetCompiland(block_id.modi);383CVSymbol sym = cii->m_debug_stream.readSymbolAtOffset(block_id.offset);384CompUnitSP comp_unit = GetOrCreateCompileUnit(*cii);385lldb::user_id_t opaque_block_uid = toOpaqueUid(block_id);386BlockSP child_block = std::make_shared<Block>(opaque_block_uid);387auto ts_or_err = GetTypeSystemForLanguage(comp_unit->GetLanguage());388if (auto err = ts_or_err.takeError())389return *child_block;390auto ts = *ts_or_err;391if (!ts)392return *child_block;393PdbAstBuilder* ast_builder = ts->GetNativePDBParser();394395switch (sym.kind()) {396case S_GPROC32:397case S_LPROC32: {398// This is a function. It must be global. Creating the Function entry399// for it automatically creates a block for it.400FunctionSP func = GetOrCreateFunction(block_id, *comp_unit);401if (func) {402Block &block = func->GetBlock(false);403if (block.GetNumRanges() == 0)404block.AddRange(Block::Range(0, func->GetAddressRange().GetByteSize()));405return block;406}407break;408}409case S_BLOCK32: {410// This is a block. Its parent is either a function or another block. In411// either case, its parent can be viewed as a block (e.g. a function412// contains 1 big block. So just get the parent block and add this block413// to it.414BlockSym block(static_cast<SymbolRecordKind>(sym.kind()));415cantFail(SymbolDeserializer::deserializeAs<BlockSym>(sym, block));416lldbassert(block.Parent != 0);417PdbCompilandSymId parent_id(block_id.modi, block.Parent);418Block &parent_block = GetOrCreateBlock(parent_id);419Function *func = parent_block.CalculateSymbolContextFunction();420lldbassert(func);421lldb::addr_t block_base =422m_index->MakeVirtualAddress(block.Segment, block.CodeOffset);423lldb::addr_t func_base =424func->GetAddressRange().GetBaseAddress().GetFileAddress();425if (block_base >= func_base)426child_block->AddRange(Block::Range(block_base - func_base, block.CodeSize));427else {428GetObjectFile()->GetModule()->ReportError(429"S_BLOCK32 at modi: {0:d} offset: {1:d}: adding range "430"[{2:x16}-{3:x16}) which has a base that is less than the "431"function's "432"low PC 0x%" PRIx64 ". Please file a bug and attach the file at the "433"start of this error message",434block_id.modi, block_id.offset, block_base,435block_base + block.CodeSize, func_base);436}437parent_block.AddChild(child_block);438ast_builder->GetOrCreateBlockDecl(block_id);439m_blocks.insert({opaque_block_uid, child_block});440break;441}442case S_INLINESITE: {443// This ensures line table is parsed first so we have inline sites info.444comp_unit->GetLineTable();445446std::shared_ptr<InlineSite> inline_site = m_inline_sites[opaque_block_uid];447Block &parent_block = GetOrCreateBlock(inline_site->parent_id);448parent_block.AddChild(child_block);449ast_builder->GetOrCreateInlinedFunctionDecl(block_id);450// Copy ranges from InlineSite to Block.451for (size_t i = 0; i < inline_site->ranges.GetSize(); ++i) {452auto *entry = inline_site->ranges.GetEntryAtIndex(i);453child_block->AddRange(454Block::Range(entry->GetRangeBase(), entry->GetByteSize()));455}456child_block->FinalizeRanges();457458// Get the inlined function callsite info.459Declaration &decl = inline_site->inline_function_info->GetDeclaration();460Declaration &callsite = inline_site->inline_function_info->GetCallSite();461child_block->SetInlinedFunctionInfo(462inline_site->inline_function_info->GetName().GetCString(), nullptr,463&decl, &callsite);464m_blocks.insert({opaque_block_uid, child_block});465break;466}467default:468lldbassert(false && "Symbol is not a block!");469}470471return *child_block;472}473474lldb::FunctionSP SymbolFileNativePDB::CreateFunction(PdbCompilandSymId func_id,475CompileUnit &comp_unit) {476const CompilandIndexItem *cci =477m_index->compilands().GetCompiland(func_id.modi);478lldbassert(cci);479CVSymbol sym_record = cci->m_debug_stream.readSymbolAtOffset(func_id.offset);480481lldbassert(sym_record.kind() == S_LPROC32 || sym_record.kind() == S_GPROC32);482SegmentOffsetLength sol = GetSegmentOffsetAndLength(sym_record);483484auto file_vm_addr =485m_index->MakeVirtualAddress(sol.so.segment, sol.so.offset);486if (file_vm_addr == LLDB_INVALID_ADDRESS || file_vm_addr == 0)487return nullptr;488489AddressRange func_range(file_vm_addr, sol.length,490comp_unit.GetModule()->GetSectionList());491if (!func_range.GetBaseAddress().IsValid())492return nullptr;493494ProcSym proc(static_cast<SymbolRecordKind>(sym_record.kind()));495cantFail(SymbolDeserializer::deserializeAs<ProcSym>(sym_record, proc));496if (proc.FunctionType == TypeIndex::None())497return nullptr;498TypeSP func_type = GetOrCreateType(proc.FunctionType);499if (!func_type)500return nullptr;501502PdbTypeSymId sig_id(proc.FunctionType, false);503Mangled mangled(proc.Name);504FunctionSP func_sp = std::make_shared<Function>(505&comp_unit, toOpaqueUid(func_id), toOpaqueUid(sig_id), mangled,506func_type.get(), func_range);507508comp_unit.AddFunction(func_sp);509510auto ts_or_err = GetTypeSystemForLanguage(comp_unit.GetLanguage());511if (auto err = ts_or_err.takeError())512return func_sp;513auto ts = *ts_or_err;514if (!ts)515return func_sp;516ts->GetNativePDBParser()->GetOrCreateFunctionDecl(func_id);517518return func_sp;519}520521CompUnitSP522SymbolFileNativePDB::CreateCompileUnit(const CompilandIndexItem &cci) {523lldb::LanguageType lang =524cci.m_compile_opts ? TranslateLanguage(cci.m_compile_opts->getLanguage())525: lldb::eLanguageTypeUnknown;526527LazyBool optimized = eLazyBoolNo;528if (cci.m_compile_opts && cci.m_compile_opts->hasOptimizations())529optimized = eLazyBoolYes;530531llvm::SmallString<64> source_file_name =532m_index->compilands().GetMainSourceFile(cci);533FileSpec fs(llvm::sys::path::convert_to_slash(534source_file_name, llvm::sys::path::Style::windows_backslash));535536CompUnitSP cu_sp = std::make_shared<CompileUnit>(537m_objfile_sp->GetModule(), nullptr, std::make_shared<SupportFile>(fs),538toOpaqueUid(cci.m_id), lang, optimized);539540SetCompileUnitAtIndex(cci.m_id.modi, cu_sp);541return cu_sp;542}543544lldb::TypeSP SymbolFileNativePDB::CreateModifierType(PdbTypeSymId type_id,545const ModifierRecord &mr,546CompilerType ct) {547TpiStream &stream = m_index->tpi();548549std::string name;550if (mr.ModifiedType.isSimple())551name = std::string(GetSimpleTypeName(mr.ModifiedType.getSimpleKind()));552else553name = computeTypeName(stream.typeCollection(), mr.ModifiedType);554Declaration decl;555lldb::TypeSP modified_type = GetOrCreateType(mr.ModifiedType);556557return MakeType(toOpaqueUid(type_id), ConstString(name),558modified_type->GetByteSize(nullptr), nullptr,559LLDB_INVALID_UID, Type::eEncodingIsUID, decl, ct,560Type::ResolveState::Full);561}562563lldb::TypeSP564SymbolFileNativePDB::CreatePointerType(PdbTypeSymId type_id,565const llvm::codeview::PointerRecord &pr,566CompilerType ct) {567TypeSP pointee = GetOrCreateType(pr.ReferentType);568if (!pointee)569return nullptr;570571if (pr.isPointerToMember()) {572MemberPointerInfo mpi = pr.getMemberInfo();573GetOrCreateType(mpi.ContainingType);574}575576Declaration decl;577return MakeType(toOpaqueUid(type_id), ConstString(), pr.getSize(), nullptr,578LLDB_INVALID_UID, Type::eEncodingIsUID, decl, ct,579Type::ResolveState::Full);580}581582lldb::TypeSP SymbolFileNativePDB::CreateSimpleType(TypeIndex ti,583CompilerType ct) {584uint64_t uid = toOpaqueUid(PdbTypeSymId(ti, false));585if (ti == TypeIndex::NullptrT()) {586Declaration decl;587return MakeType(uid, ConstString("std::nullptr_t"), 0, nullptr,588LLDB_INVALID_UID, Type::eEncodingIsUID, decl, ct,589Type::ResolveState::Full);590}591592if (ti.getSimpleMode() != SimpleTypeMode::Direct) {593TypeSP direct_sp = GetOrCreateType(ti.makeDirect());594uint32_t pointer_size = 0;595switch (ti.getSimpleMode()) {596case SimpleTypeMode::FarPointer32:597case SimpleTypeMode::NearPointer32:598pointer_size = 4;599break;600case SimpleTypeMode::NearPointer64:601pointer_size = 8;602break;603default:604// 128-bit and 16-bit pointers unsupported.605return nullptr;606}607Declaration decl;608return MakeType(uid, ConstString(), pointer_size, nullptr, LLDB_INVALID_UID,609Type::eEncodingIsUID, decl, ct, Type::ResolveState::Full);610}611612if (ti.getSimpleKind() == SimpleTypeKind::NotTranslated)613return nullptr;614615size_t size = GetTypeSizeForSimpleKind(ti.getSimpleKind());616llvm::StringRef type_name = GetSimpleTypeName(ti.getSimpleKind());617618Declaration decl;619return MakeType(uid, ConstString(type_name), size, nullptr, LLDB_INVALID_UID,620Type::eEncodingIsUID, decl, ct, Type::ResolveState::Full);621}622623static std::string GetUnqualifiedTypeName(const TagRecord &record) {624if (!record.hasUniqueName()) {625MSVCUndecoratedNameParser parser(record.Name);626llvm::ArrayRef<MSVCUndecoratedNameSpecifier> specs = parser.GetSpecifiers();627628return std::string(specs.back().GetBaseName());629}630631llvm::ms_demangle::Demangler demangler;632std::string_view sv(record.UniqueName.begin(), record.UniqueName.size());633llvm::ms_demangle::TagTypeNode *ttn = demangler.parseTagUniqueName(sv);634if (demangler.Error)635return std::string(record.Name);636637llvm::ms_demangle::IdentifierNode *idn =638ttn->QualifiedName->getUnqualifiedIdentifier();639return idn->toString();640}641642lldb::TypeSP643SymbolFileNativePDB::CreateClassStructUnion(PdbTypeSymId type_id,644const TagRecord &record,645size_t size, CompilerType ct) {646647std::string uname = GetUnqualifiedTypeName(record);648649// FIXME: Search IPI stream for LF_UDT_MOD_SRC_LINE.650Declaration decl;651return MakeType(toOpaqueUid(type_id), ConstString(uname), size, nullptr,652LLDB_INVALID_UID, Type::eEncodingIsUID, decl, ct,653Type::ResolveState::Forward);654}655656lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbTypeSymId type_id,657const ClassRecord &cr,658CompilerType ct) {659return CreateClassStructUnion(type_id, cr, cr.getSize(), ct);660}661662lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbTypeSymId type_id,663const UnionRecord &ur,664CompilerType ct) {665return CreateClassStructUnion(type_id, ur, ur.getSize(), ct);666}667668lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbTypeSymId type_id,669const EnumRecord &er,670CompilerType ct) {671std::string uname = GetUnqualifiedTypeName(er);672673Declaration decl;674TypeSP underlying_type = GetOrCreateType(er.UnderlyingType);675676return MakeType(toOpaqueUid(type_id), ConstString(uname),677underlying_type->GetByteSize(nullptr), nullptr,678LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl,679ct, lldb_private::Type::ResolveState::Forward);680}681682TypeSP SymbolFileNativePDB::CreateArrayType(PdbTypeSymId type_id,683const ArrayRecord &ar,684CompilerType ct) {685TypeSP element_type = GetOrCreateType(ar.ElementType);686687Declaration decl;688TypeSP array_sp =689MakeType(toOpaqueUid(type_id), ConstString(), ar.Size, nullptr,690LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, ct,691lldb_private::Type::ResolveState::Full);692array_sp->SetEncodingType(element_type.get());693return array_sp;694}695696TypeSP SymbolFileNativePDB::CreateFunctionType(PdbTypeSymId type_id,697const MemberFunctionRecord &mfr,698CompilerType ct) {699Declaration decl;700return MakeType(toOpaqueUid(type_id), ConstString(), 0, nullptr,701LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl,702ct, lldb_private::Type::ResolveState::Full);703}704705TypeSP SymbolFileNativePDB::CreateProcedureType(PdbTypeSymId type_id,706const ProcedureRecord &pr,707CompilerType ct) {708Declaration decl;709return MakeType(toOpaqueUid(type_id), ConstString(), 0, nullptr,710LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl,711ct, lldb_private::Type::ResolveState::Full);712}713714TypeSP SymbolFileNativePDB::CreateType(PdbTypeSymId type_id, CompilerType ct) {715if (type_id.index.isSimple())716return CreateSimpleType(type_id.index, ct);717718TpiStream &stream = type_id.is_ipi ? m_index->ipi() : m_index->tpi();719CVType cvt = stream.getType(type_id.index);720721if (cvt.kind() == LF_MODIFIER) {722ModifierRecord modifier;723llvm::cantFail(724TypeDeserializer::deserializeAs<ModifierRecord>(cvt, modifier));725return CreateModifierType(type_id, modifier, ct);726}727728if (cvt.kind() == LF_POINTER) {729PointerRecord pointer;730llvm::cantFail(731TypeDeserializer::deserializeAs<PointerRecord>(cvt, pointer));732return CreatePointerType(type_id, pointer, ct);733}734735if (IsClassRecord(cvt.kind())) {736ClassRecord cr;737llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, cr));738return CreateTagType(type_id, cr, ct);739}740741if (cvt.kind() == LF_ENUM) {742EnumRecord er;743llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));744return CreateTagType(type_id, er, ct);745}746747if (cvt.kind() == LF_UNION) {748UnionRecord ur;749llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, ur));750return CreateTagType(type_id, ur, ct);751}752753if (cvt.kind() == LF_ARRAY) {754ArrayRecord ar;755llvm::cantFail(TypeDeserializer::deserializeAs<ArrayRecord>(cvt, ar));756return CreateArrayType(type_id, ar, ct);757}758759if (cvt.kind() == LF_PROCEDURE) {760ProcedureRecord pr;761llvm::cantFail(TypeDeserializer::deserializeAs<ProcedureRecord>(cvt, pr));762return CreateProcedureType(type_id, pr, ct);763}764if (cvt.kind() == LF_MFUNCTION) {765MemberFunctionRecord mfr;766llvm::cantFail(TypeDeserializer::deserializeAs<MemberFunctionRecord>(cvt, mfr));767return CreateFunctionType(type_id, mfr, ct);768}769770return nullptr;771}772773TypeSP SymbolFileNativePDB::CreateAndCacheType(PdbTypeSymId type_id) {774// If they search for a UDT which is a forward ref, try and resolve the full775// decl and just map the forward ref uid to the full decl record.776std::optional<PdbTypeSymId> full_decl_uid;777if (IsForwardRefUdt(type_id, m_index->tpi())) {778auto expected_full_ti =779m_index->tpi().findFullDeclForForwardRef(type_id.index);780if (!expected_full_ti)781llvm::consumeError(expected_full_ti.takeError());782else if (*expected_full_ti != type_id.index) {783full_decl_uid = PdbTypeSymId(*expected_full_ti, false);784785// It's possible that a lookup would occur for the full decl causing it786// to be cached, then a second lookup would occur for the forward decl.787// We don't want to create a second full decl, so make sure the full788// decl hasn't already been cached.789auto full_iter = m_types.find(toOpaqueUid(*full_decl_uid));790if (full_iter != m_types.end()) {791TypeSP result = full_iter->second;792// Map the forward decl to the TypeSP for the full decl so we can take793// the fast path next time.794m_types[toOpaqueUid(type_id)] = result;795return result;796}797}798}799800PdbTypeSymId best_decl_id = full_decl_uid ? *full_decl_uid : type_id;801auto ts_or_err = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);802if (auto err = ts_or_err.takeError())803return nullptr;804auto ts = *ts_or_err;805if (!ts)806return nullptr;807808PdbAstBuilder* ast_builder = ts->GetNativePDBParser();809clang::QualType qt = ast_builder->GetOrCreateType(best_decl_id);810if (qt.isNull())811return nullptr;812813TypeSP result = CreateType(best_decl_id, ast_builder->ToCompilerType(qt));814if (!result)815return nullptr;816817uint64_t best_uid = toOpaqueUid(best_decl_id);818m_types[best_uid] = result;819// If we had both a forward decl and a full decl, make both point to the new820// type.821if (full_decl_uid)822m_types[toOpaqueUid(type_id)] = result;823824return result;825}826827TypeSP SymbolFileNativePDB::GetOrCreateType(PdbTypeSymId type_id) {828// We can't use try_emplace / overwrite here because the process of creating829// a type could create nested types, which could invalidate iterators. So830// we have to do a 2-phase lookup / insert.831auto iter = m_types.find(toOpaqueUid(type_id));832if (iter != m_types.end())833return iter->second;834835TypeSP type = CreateAndCacheType(type_id);836if (type)837GetTypeList().Insert(type);838return type;839}840841VariableSP SymbolFileNativePDB::CreateGlobalVariable(PdbGlobalSymId var_id) {842CVSymbol sym = m_index->symrecords().readRecord(var_id.offset);843if (sym.kind() == S_CONSTANT)844return CreateConstantSymbol(var_id, sym);845846lldb::ValueType scope = eValueTypeInvalid;847TypeIndex ti;848llvm::StringRef name;849lldb::addr_t addr = 0;850uint16_t section = 0;851uint32_t offset = 0;852bool is_external = false;853switch (sym.kind()) {854case S_GDATA32:855is_external = true;856[[fallthrough]];857case S_LDATA32: {858DataSym ds(sym.kind());859llvm::cantFail(SymbolDeserializer::deserializeAs<DataSym>(sym, ds));860ti = ds.Type;861scope = (sym.kind() == S_GDATA32) ? eValueTypeVariableGlobal862: eValueTypeVariableStatic;863name = ds.Name;864section = ds.Segment;865offset = ds.DataOffset;866addr = m_index->MakeVirtualAddress(ds.Segment, ds.DataOffset);867break;868}869case S_GTHREAD32:870is_external = true;871[[fallthrough]];872case S_LTHREAD32: {873ThreadLocalDataSym tlds(sym.kind());874llvm::cantFail(875SymbolDeserializer::deserializeAs<ThreadLocalDataSym>(sym, tlds));876ti = tlds.Type;877name = tlds.Name;878section = tlds.Segment;879offset = tlds.DataOffset;880addr = m_index->MakeVirtualAddress(tlds.Segment, tlds.DataOffset);881scope = eValueTypeVariableThreadLocal;882break;883}884default:885llvm_unreachable("unreachable!");886}887888CompUnitSP comp_unit;889std::optional<uint16_t> modi = m_index->GetModuleIndexForVa(addr);890if (!modi) {891return nullptr;892}893894CompilandIndexItem &cci = m_index->compilands().GetOrCreateCompiland(*modi);895comp_unit = GetOrCreateCompileUnit(cci);896897Declaration decl;898PdbTypeSymId tid(ti, false);899SymbolFileTypeSP type_sp =900std::make_shared<SymbolFileType>(*this, toOpaqueUid(tid));901Variable::RangeList ranges;902auto ts_or_err = GetTypeSystemForLanguage(comp_unit->GetLanguage());903if (auto err = ts_or_err.takeError())904return nullptr;905auto ts = *ts_or_err;906if (!ts)907return nullptr;908909ts->GetNativePDBParser()->GetOrCreateVariableDecl(var_id);910911ModuleSP module_sp = GetObjectFile()->GetModule();912DWARFExpressionList location(913module_sp, MakeGlobalLocationExpression(section, offset, module_sp),914nullptr);915916std::string global_name("::");917global_name += name;918bool artificial = false;919bool location_is_constant_data = false;920bool static_member = false;921VariableSP var_sp = std::make_shared<Variable>(922toOpaqueUid(var_id), name.str().c_str(), global_name.c_str(), type_sp,923scope, comp_unit.get(), ranges, &decl, location, is_external, artificial,924location_is_constant_data, static_member);925926return var_sp;927}928929lldb::VariableSP930SymbolFileNativePDB::CreateConstantSymbol(PdbGlobalSymId var_id,931const CVSymbol &cvs) {932TpiStream &tpi = m_index->tpi();933ConstantSym constant(cvs.kind());934935llvm::cantFail(SymbolDeserializer::deserializeAs<ConstantSym>(cvs, constant));936std::string global_name("::");937global_name += constant.Name;938PdbTypeSymId tid(constant.Type, false);939SymbolFileTypeSP type_sp =940std::make_shared<SymbolFileType>(*this, toOpaqueUid(tid));941942Declaration decl;943Variable::RangeList ranges;944ModuleSP module = GetObjectFile()->GetModule();945DWARFExpressionList location(module,946MakeConstantLocationExpression(947constant.Type, tpi, constant.Value, module),948nullptr);949950bool external = false;951bool artificial = false;952bool location_is_constant_data = true;953bool static_member = false;954VariableSP var_sp = std::make_shared<Variable>(955toOpaqueUid(var_id), constant.Name.str().c_str(), global_name.c_str(),956type_sp, eValueTypeVariableGlobal, module.get(), ranges, &decl, location,957external, artificial, location_is_constant_data, static_member);958return var_sp;959}960961VariableSP962SymbolFileNativePDB::GetOrCreateGlobalVariable(PdbGlobalSymId var_id) {963auto emplace_result = m_global_vars.try_emplace(toOpaqueUid(var_id), nullptr);964if (emplace_result.second) {965if (VariableSP var_sp = CreateGlobalVariable(var_id))966emplace_result.first->second = var_sp;967else968return nullptr;969}970971return emplace_result.first->second;972}973974lldb::TypeSP SymbolFileNativePDB::GetOrCreateType(TypeIndex ti) {975return GetOrCreateType(PdbTypeSymId(ti, false));976}977978FunctionSP SymbolFileNativePDB::GetOrCreateFunction(PdbCompilandSymId func_id,979CompileUnit &comp_unit) {980auto emplace_result = m_functions.try_emplace(toOpaqueUid(func_id), nullptr);981if (emplace_result.second)982emplace_result.first->second = CreateFunction(func_id, comp_unit);983984return emplace_result.first->second;985}986987CompUnitSP988SymbolFileNativePDB::GetOrCreateCompileUnit(const CompilandIndexItem &cci) {989990auto emplace_result =991m_compilands.try_emplace(toOpaqueUid(cci.m_id), nullptr);992if (emplace_result.second)993emplace_result.first->second = CreateCompileUnit(cci);994995lldbassert(emplace_result.first->second);996return emplace_result.first->second;997}998999Block &SymbolFileNativePDB::GetOrCreateBlock(PdbCompilandSymId block_id) {1000auto iter = m_blocks.find(toOpaqueUid(block_id));1001if (iter != m_blocks.end())1002return *iter->second;10031004return CreateBlock(block_id);1005}10061007void SymbolFileNativePDB::ParseDeclsForContext(1008lldb_private::CompilerDeclContext decl_ctx) {1009TypeSystem* ts_or_err = decl_ctx.GetTypeSystem();1010if (!ts_or_err)1011return;1012PdbAstBuilder* ast_builder = ts_or_err->GetNativePDBParser();1013clang::DeclContext *context = ast_builder->FromCompilerDeclContext(decl_ctx);1014if (!context)1015return;1016ast_builder->ParseDeclsForContext(*context);1017}10181019lldb::CompUnitSP SymbolFileNativePDB::ParseCompileUnitAtIndex(uint32_t index) {1020if (index >= GetNumCompileUnits())1021return CompUnitSP();1022lldbassert(index < UINT16_MAX);1023if (index >= UINT16_MAX)1024return nullptr;10251026CompilandIndexItem &item = m_index->compilands().GetOrCreateCompiland(index);10271028return GetOrCreateCompileUnit(item);1029}10301031lldb::LanguageType SymbolFileNativePDB::ParseLanguage(CompileUnit &comp_unit) {1032std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());1033PdbSymUid uid(comp_unit.GetID());1034lldbassert(uid.kind() == PdbSymUidKind::Compiland);10351036CompilandIndexItem *item =1037m_index->compilands().GetCompiland(uid.asCompiland().modi);1038lldbassert(item);1039if (!item->m_compile_opts)1040return lldb::eLanguageTypeUnknown;10411042return TranslateLanguage(item->m_compile_opts->getLanguage());1043}10441045void SymbolFileNativePDB::AddSymbols(Symtab &symtab) {}10461047size_t SymbolFileNativePDB::ParseFunctions(CompileUnit &comp_unit) {1048std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());1049PdbSymUid uid{comp_unit.GetID()};1050lldbassert(uid.kind() == PdbSymUidKind::Compiland);1051uint16_t modi = uid.asCompiland().modi;1052CompilandIndexItem &cii = m_index->compilands().GetOrCreateCompiland(modi);10531054size_t count = comp_unit.GetNumFunctions();1055const CVSymbolArray &syms = cii.m_debug_stream.getSymbolArray();1056for (auto iter = syms.begin(); iter != syms.end(); ++iter) {1057if (iter->kind() != S_LPROC32 && iter->kind() != S_GPROC32)1058continue;10591060PdbCompilandSymId sym_id{modi, iter.offset()};10611062FunctionSP func = GetOrCreateFunction(sym_id, comp_unit);1063}10641065size_t new_count = comp_unit.GetNumFunctions();1066lldbassert(new_count >= count);1067return new_count - count;1068}10691070static bool NeedsResolvedCompileUnit(uint32_t resolve_scope) {1071// If any of these flags are set, we need to resolve the compile unit.1072uint32_t flags = eSymbolContextCompUnit;1073flags |= eSymbolContextVariable;1074flags |= eSymbolContextFunction;1075flags |= eSymbolContextBlock;1076flags |= eSymbolContextLineEntry;1077return (resolve_scope & flags) != 0;1078}10791080uint32_t SymbolFileNativePDB::ResolveSymbolContext(1081const Address &addr, SymbolContextItem resolve_scope, SymbolContext &sc) {1082std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());1083uint32_t resolved_flags = 0;1084lldb::addr_t file_addr = addr.GetFileAddress();10851086if (NeedsResolvedCompileUnit(resolve_scope)) {1087std::optional<uint16_t> modi = m_index->GetModuleIndexForVa(file_addr);1088if (!modi)1089return 0;1090CompUnitSP cu_sp = GetCompileUnitAtIndex(*modi);1091if (!cu_sp)1092return 0;10931094sc.comp_unit = cu_sp.get();1095resolved_flags |= eSymbolContextCompUnit;1096}10971098if (resolve_scope & eSymbolContextFunction ||1099resolve_scope & eSymbolContextBlock) {1100lldbassert(sc.comp_unit);1101std::vector<SymbolAndUid> matches = m_index->FindSymbolsByVa(file_addr);1102// Search the matches in reverse. This way if there are multiple matches1103// (for example we are 3 levels deep in a nested scope) it will find the1104// innermost one first.1105for (const auto &match : llvm::reverse(matches)) {1106if (match.uid.kind() != PdbSymUidKind::CompilandSym)1107continue;11081109PdbCompilandSymId csid = match.uid.asCompilandSym();1110CVSymbol cvs = m_index->ReadSymbolRecord(csid);1111PDB_SymType type = CVSymToPDBSym(cvs.kind());1112if (type != PDB_SymType::Function && type != PDB_SymType::Block)1113continue;1114if (type == PDB_SymType::Function) {1115sc.function = GetOrCreateFunction(csid, *sc.comp_unit).get();1116if (sc.function) {1117Block &block = sc.function->GetBlock(true);1118addr_t func_base =1119sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();1120addr_t offset = file_addr - func_base;1121sc.block = block.FindInnermostBlockByOffset(offset);1122}1123}11241125if (type == PDB_SymType::Block) {1126Block &block = GetOrCreateBlock(csid);1127sc.function = block.CalculateSymbolContextFunction();1128if (sc.function) {1129sc.function->GetBlock(true);1130addr_t func_base =1131sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();1132addr_t offset = file_addr - func_base;1133sc.block = block.FindInnermostBlockByOffset(offset);1134}1135}1136if (sc.function)1137resolved_flags |= eSymbolContextFunction;1138if (sc.block)1139resolved_flags |= eSymbolContextBlock;1140break;1141}1142}11431144if (resolve_scope & eSymbolContextLineEntry) {1145lldbassert(sc.comp_unit);1146if (auto *line_table = sc.comp_unit->GetLineTable()) {1147if (line_table->FindLineEntryByAddress(addr, sc.line_entry))1148resolved_flags |= eSymbolContextLineEntry;1149}1150}11511152return resolved_flags;1153}11541155uint32_t SymbolFileNativePDB::ResolveSymbolContext(1156const SourceLocationSpec &src_location_spec,1157lldb::SymbolContextItem resolve_scope, SymbolContextList &sc_list) {1158std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());1159const uint32_t prev_size = sc_list.GetSize();1160if (resolve_scope & eSymbolContextCompUnit) {1161for (uint32_t cu_idx = 0, num_cus = GetNumCompileUnits(); cu_idx < num_cus;1162++cu_idx) {1163CompileUnit *cu = ParseCompileUnitAtIndex(cu_idx).get();1164if (!cu)1165continue;11661167bool file_spec_matches_cu_file_spec = FileSpec::Match(1168src_location_spec.GetFileSpec(), cu->GetPrimaryFile());1169if (file_spec_matches_cu_file_spec) {1170cu->ResolveSymbolContext(src_location_spec, resolve_scope, sc_list);1171break;1172}1173}1174}1175return sc_list.GetSize() - prev_size;1176}11771178bool SymbolFileNativePDB::ParseLineTable(CompileUnit &comp_unit) {1179// Unfortunately LLDB is set up to parse the entire compile unit line table1180// all at once, even if all it really needs is line info for a specific1181// function. In the future it would be nice if it could set the sc.m_function1182// member, and we could only get the line info for the function in question.1183std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());1184PdbSymUid cu_id(comp_unit.GetID());1185lldbassert(cu_id.kind() == PdbSymUidKind::Compiland);1186uint16_t modi = cu_id.asCompiland().modi;1187CompilandIndexItem *cii = m_index->compilands().GetCompiland(modi);1188lldbassert(cii);11891190// Parse DEBUG_S_LINES subsections first, then parse all S_INLINESITE records1191// in this CU. Add line entries into the set first so that if there are line1192// entries with same addres, the later is always more accurate than the1193// former.1194std::set<LineTable::Entry, LineTableEntryComparator> line_set;11951196// This is basically a copy of the .debug$S subsections from all original COFF1197// object files merged together with address relocations applied. We are1198// looking for all DEBUG_S_LINES subsections.1199for (const DebugSubsectionRecord &dssr :1200cii->m_debug_stream.getSubsectionsArray()) {1201if (dssr.kind() != DebugSubsectionKind::Lines)1202continue;12031204DebugLinesSubsectionRef lines;1205llvm::BinaryStreamReader reader(dssr.getRecordData());1206if (auto EC = lines.initialize(reader)) {1207llvm::consumeError(std::move(EC));1208return false;1209}12101211const LineFragmentHeader *lfh = lines.header();1212uint64_t virtual_addr =1213m_index->MakeVirtualAddress(lfh->RelocSegment, lfh->RelocOffset);1214if (virtual_addr == LLDB_INVALID_ADDRESS)1215continue;12161217for (const LineColumnEntry &group : lines) {1218llvm::Expected<uint32_t> file_index_or_err =1219GetFileIndex(*cii, group.NameIndex);1220if (!file_index_or_err)1221continue;1222uint32_t file_index = file_index_or_err.get();1223lldbassert(!group.LineNumbers.empty());1224CompilandIndexItem::GlobalLineTable::Entry line_entry(1225LLDB_INVALID_ADDRESS, 0);1226for (const LineNumberEntry &entry : group.LineNumbers) {1227LineInfo cur_info(entry.Flags);12281229if (cur_info.isAlwaysStepInto() || cur_info.isNeverStepInto())1230continue;12311232uint64_t addr = virtual_addr + entry.Offset;12331234bool is_statement = cur_info.isStatement();1235bool is_prologue = IsFunctionPrologue(*cii, addr);1236bool is_epilogue = IsFunctionEpilogue(*cii, addr);12371238uint32_t lno = cur_info.getStartLine();12391240LineTable::Entry new_entry(addr, lno, 0, file_index, is_statement, false,1241is_prologue, is_epilogue, false);1242// Terminal entry has lower precedence than new entry.1243auto iter = line_set.find(new_entry);1244if (iter != line_set.end() && iter->is_terminal_entry)1245line_set.erase(iter);1246line_set.insert(new_entry);12471248if (line_entry.GetRangeBase() != LLDB_INVALID_ADDRESS) {1249line_entry.SetRangeEnd(addr);1250cii->m_global_line_table.Append(line_entry);1251}1252line_entry.SetRangeBase(addr);1253line_entry.data = {file_index, lno};1254}1255LineInfo last_line(group.LineNumbers.back().Flags);1256line_set.emplace(virtual_addr + lfh->CodeSize, last_line.getEndLine(), 0,1257file_index, false, false, false, false, true);12581259if (line_entry.GetRangeBase() != LLDB_INVALID_ADDRESS) {1260line_entry.SetRangeEnd(virtual_addr + lfh->CodeSize);1261cii->m_global_line_table.Append(line_entry);1262}1263}1264}12651266cii->m_global_line_table.Sort();12671268// Parse all S_INLINESITE in this CU.1269const CVSymbolArray &syms = cii->m_debug_stream.getSymbolArray();1270for (auto iter = syms.begin(); iter != syms.end();) {1271if (iter->kind() != S_LPROC32 && iter->kind() != S_GPROC32) {1272++iter;1273continue;1274}12751276uint32_t record_offset = iter.offset();1277CVSymbol func_record =1278cii->m_debug_stream.readSymbolAtOffset(record_offset);1279SegmentOffsetLength sol = GetSegmentOffsetAndLength(func_record);1280addr_t file_vm_addr =1281m_index->MakeVirtualAddress(sol.so.segment, sol.so.offset);1282if (file_vm_addr == LLDB_INVALID_ADDRESS)1283continue;12841285AddressRange func_range(file_vm_addr, sol.length,1286comp_unit.GetModule()->GetSectionList());1287Address func_base = func_range.GetBaseAddress();1288PdbCompilandSymId func_id{modi, record_offset};12891290// Iterate all S_INLINESITEs in the function.1291auto parse_inline_sites = [&](SymbolKind kind, PdbCompilandSymId id) {1292if (kind != S_INLINESITE)1293return false;12941295ParseInlineSite(id, func_base);12961297for (const auto &line_entry :1298m_inline_sites[toOpaqueUid(id)]->line_entries) {1299// If line_entry is not terminal entry, remove previous line entry at1300// the same address and insert new one. Terminal entry inside an inline1301// site might not be terminal entry for its parent.1302if (!line_entry.is_terminal_entry)1303line_set.erase(line_entry);1304line_set.insert(line_entry);1305}1306// No longer useful after adding to line_set.1307m_inline_sites[toOpaqueUid(id)]->line_entries.clear();1308return true;1309};1310ParseSymbolArrayInScope(func_id, parse_inline_sites);1311// Jump to the end of the function record.1312iter = syms.at(getScopeEndOffset(func_record));1313}13141315cii->m_global_line_table.Clear();13161317// Add line entries in line_set to line_table.1318auto line_table = std::make_unique<LineTable>(&comp_unit);1319std::unique_ptr<LineSequence> sequence(1320line_table->CreateLineSequenceContainer());1321for (const auto &line_entry : line_set) {1322line_table->AppendLineEntryToSequence(1323sequence.get(), line_entry.file_addr, line_entry.line,1324line_entry.column, line_entry.file_idx,1325line_entry.is_start_of_statement, line_entry.is_start_of_basic_block,1326line_entry.is_prologue_end, line_entry.is_epilogue_begin,1327line_entry.is_terminal_entry);1328}1329line_table->InsertSequence(sequence.get());13301331if (line_table->GetSize() == 0)1332return false;13331334comp_unit.SetLineTable(line_table.release());1335return true;1336}13371338bool SymbolFileNativePDB::ParseDebugMacros(CompileUnit &comp_unit) {1339// PDB doesn't contain information about macros1340return false;1341}13421343llvm::Expected<uint32_t>1344SymbolFileNativePDB::GetFileIndex(const CompilandIndexItem &cii,1345uint32_t file_id) {1346if (!cii.m_strings.hasChecksums() || !cii.m_strings.hasStrings())1347return llvm::make_error<RawError>(raw_error_code::no_entry);13481349const auto &checksums = cii.m_strings.checksums().getArray();1350const auto &strings = cii.m_strings.strings();1351// Indices in this structure are actually offsets of records in the1352// DEBUG_S_FILECHECKSUMS subsection. Those entries then have an index1353// into the global PDB string table.1354auto iter = checksums.at(file_id);1355if (iter == checksums.end())1356return llvm::make_error<RawError>(raw_error_code::no_entry);13571358llvm::Expected<llvm::StringRef> efn = strings.getString(iter->FileNameOffset);1359if (!efn) {1360return efn.takeError();1361}13621363// LLDB wants the index of the file in the list of support files.1364auto fn_iter = llvm::find(cii.m_file_list, *efn);1365if (fn_iter != cii.m_file_list.end())1366return std::distance(cii.m_file_list.begin(), fn_iter);1367return llvm::make_error<RawError>(raw_error_code::no_entry);1368}13691370bool SymbolFileNativePDB::ParseSupportFiles(CompileUnit &comp_unit,1371SupportFileList &support_files) {1372std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());1373PdbSymUid cu_id(comp_unit.GetID());1374lldbassert(cu_id.kind() == PdbSymUidKind::Compiland);1375CompilandIndexItem *cci =1376m_index->compilands().GetCompiland(cu_id.asCompiland().modi);1377lldbassert(cci);13781379for (llvm::StringRef f : cci->m_file_list) {1380FileSpec::Style style =1381f.starts_with("/") ? FileSpec::Style::posix : FileSpec::Style::windows;1382FileSpec spec(f, style);1383support_files.Append(spec);1384}1385return true;1386}13871388bool SymbolFileNativePDB::ParseImportedModules(1389const SymbolContext &sc, std::vector<SourceModule> &imported_modules) {1390// PDB does not yet support module debug info1391return false;1392}13931394void SymbolFileNativePDB::ParseInlineSite(PdbCompilandSymId id,1395Address func_addr) {1396lldb::user_id_t opaque_uid = toOpaqueUid(id);1397if (m_inline_sites.contains(opaque_uid))1398return;13991400addr_t func_base = func_addr.GetFileAddress();1401CompilandIndexItem *cii = m_index->compilands().GetCompiland(id.modi);1402CVSymbol sym = cii->m_debug_stream.readSymbolAtOffset(id.offset);1403CompUnitSP comp_unit = GetOrCreateCompileUnit(*cii);14041405InlineSiteSym inline_site(static_cast<SymbolRecordKind>(sym.kind()));1406cantFail(SymbolDeserializer::deserializeAs<InlineSiteSym>(sym, inline_site));1407PdbCompilandSymId parent_id(id.modi, inline_site.Parent);14081409std::shared_ptr<InlineSite> inline_site_sp =1410std::make_shared<InlineSite>(parent_id);14111412// Get the inlined function declaration info.1413auto iter = cii->m_inline_map.find(inline_site.Inlinee);1414if (iter == cii->m_inline_map.end())1415return;1416InlineeSourceLine inlinee_line = iter->second;14171418const SupportFileList &files = comp_unit->GetSupportFiles();1419FileSpec decl_file;1420llvm::Expected<uint32_t> file_index_or_err =1421GetFileIndex(*cii, inlinee_line.Header->FileID);1422if (!file_index_or_err)1423return;1424uint32_t file_offset = file_index_or_err.get();1425decl_file = files.GetFileSpecAtIndex(file_offset);1426uint32_t decl_line = inlinee_line.Header->SourceLineNum;1427std::unique_ptr<Declaration> decl_up =1428std::make_unique<Declaration>(decl_file, decl_line);14291430// Parse range and line info.1431uint32_t code_offset = 0;1432int32_t line_offset = 0;1433std::optional<uint32_t> code_offset_base;1434std::optional<uint32_t> code_offset_end;1435std::optional<int32_t> cur_line_offset;1436std::optional<int32_t> next_line_offset;1437std::optional<uint32_t> next_file_offset;14381439bool is_terminal_entry = false;1440bool is_start_of_statement = true;1441// The first instruction is the prologue end.1442bool is_prologue_end = true;14431444auto update_code_offset = [&](uint32_t code_delta) {1445if (!code_offset_base)1446code_offset_base = code_offset;1447else if (!code_offset_end)1448code_offset_end = *code_offset_base + code_delta;1449};1450auto update_line_offset = [&](int32_t line_delta) {1451line_offset += line_delta;1452if (!code_offset_base || !cur_line_offset)1453cur_line_offset = line_offset;1454else1455next_line_offset = line_offset;1456;1457};1458auto update_file_offset = [&](uint32_t offset) {1459if (!code_offset_base)1460file_offset = offset;1461else1462next_file_offset = offset;1463};14641465for (auto &annot : inline_site.annotations()) {1466switch (annot.OpCode) {1467case BinaryAnnotationsOpCode::CodeOffset:1468case BinaryAnnotationsOpCode::ChangeCodeOffset:1469case BinaryAnnotationsOpCode::ChangeCodeOffsetBase:1470code_offset += annot.U1;1471update_code_offset(annot.U1);1472break;1473case BinaryAnnotationsOpCode::ChangeLineOffset:1474update_line_offset(annot.S1);1475break;1476case BinaryAnnotationsOpCode::ChangeCodeLength:1477update_code_offset(annot.U1);1478code_offset += annot.U1;1479is_terminal_entry = true;1480break;1481case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset:1482code_offset += annot.U1;1483update_code_offset(annot.U1);1484update_line_offset(annot.S1);1485break;1486case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset:1487code_offset += annot.U2;1488update_code_offset(annot.U2);1489update_code_offset(annot.U1);1490code_offset += annot.U1;1491is_terminal_entry = true;1492break;1493case BinaryAnnotationsOpCode::ChangeFile:1494update_file_offset(annot.U1);1495break;1496default:1497break;1498}14991500// Add range if current range is finished.1501if (code_offset_base && code_offset_end && cur_line_offset) {1502inline_site_sp->ranges.Append(RangeSourceLineVector::Entry(1503*code_offset_base, *code_offset_end - *code_offset_base,1504decl_line + *cur_line_offset));1505// Set base, end, file offset and line offset for next range.1506if (next_file_offset)1507file_offset = *next_file_offset;1508if (next_line_offset) {1509cur_line_offset = next_line_offset;1510next_line_offset = std::nullopt;1511}1512code_offset_base = is_terminal_entry ? std::nullopt : code_offset_end;1513code_offset_end = next_file_offset = std::nullopt;1514}1515if (code_offset_base && cur_line_offset) {1516if (is_terminal_entry) {1517LineTable::Entry line_entry(1518func_base + *code_offset_base, decl_line + *cur_line_offset, 0,1519file_offset, false, false, false, false, true);1520inline_site_sp->line_entries.push_back(line_entry);1521} else {1522LineTable::Entry line_entry(func_base + *code_offset_base,1523decl_line + *cur_line_offset, 0,1524file_offset, is_start_of_statement, false,1525is_prologue_end, false, false);1526inline_site_sp->line_entries.push_back(line_entry);1527is_prologue_end = false;1528is_start_of_statement = false;1529}1530}1531if (is_terminal_entry)1532is_start_of_statement = true;1533is_terminal_entry = false;1534}15351536inline_site_sp->ranges.Sort();15371538// Get the inlined function callsite info.1539std::unique_ptr<Declaration> callsite_up;1540if (!inline_site_sp->ranges.IsEmpty()) {1541auto *entry = inline_site_sp->ranges.GetEntryAtIndex(0);1542addr_t base_offset = entry->GetRangeBase();1543if (cii->m_debug_stream.readSymbolAtOffset(parent_id.offset).kind() ==1544S_INLINESITE) {1545// Its parent is another inline site, lookup parent site's range vector1546// for callsite line.1547ParseInlineSite(parent_id, func_base);1548std::shared_ptr<InlineSite> parent_site =1549m_inline_sites[toOpaqueUid(parent_id)];1550FileSpec &parent_decl_file =1551parent_site->inline_function_info->GetDeclaration().GetFile();1552if (auto *parent_entry =1553parent_site->ranges.FindEntryThatContains(base_offset)) {1554callsite_up =1555std::make_unique<Declaration>(parent_decl_file, parent_entry->data);1556}1557} else {1558// Its parent is a function, lookup global line table for callsite.1559if (auto *entry = cii->m_global_line_table.FindEntryThatContains(1560func_base + base_offset)) {1561const FileSpec &callsite_file =1562files.GetFileSpecAtIndex(entry->data.first);1563callsite_up =1564std::make_unique<Declaration>(callsite_file, entry->data.second);1565}1566}1567}15681569// Get the inlined function name.1570CVType inlinee_cvt = m_index->ipi().getType(inline_site.Inlinee);1571std::string inlinee_name;1572if (inlinee_cvt.kind() == LF_MFUNC_ID) {1573MemberFuncIdRecord mfr;1574cantFail(1575TypeDeserializer::deserializeAs<MemberFuncIdRecord>(inlinee_cvt, mfr));1576LazyRandomTypeCollection &types = m_index->tpi().typeCollection();1577inlinee_name.append(std::string(types.getTypeName(mfr.ClassType)));1578inlinee_name.append("::");1579inlinee_name.append(mfr.getName().str());1580} else if (inlinee_cvt.kind() == LF_FUNC_ID) {1581FuncIdRecord fir;1582cantFail(TypeDeserializer::deserializeAs<FuncIdRecord>(inlinee_cvt, fir));1583TypeIndex parent_idx = fir.getParentScope();1584if (!parent_idx.isNoneType()) {1585LazyRandomTypeCollection &ids = m_index->ipi().typeCollection();1586inlinee_name.append(std::string(ids.getTypeName(parent_idx)));1587inlinee_name.append("::");1588}1589inlinee_name.append(fir.getName().str());1590}1591inline_site_sp->inline_function_info = std::make_shared<InlineFunctionInfo>(1592inlinee_name.c_str(), llvm::StringRef(), decl_up.get(),1593callsite_up.get());15941595m_inline_sites[opaque_uid] = inline_site_sp;1596}15971598size_t SymbolFileNativePDB::ParseBlocksRecursive(Function &func) {1599std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());1600PdbCompilandSymId func_id = PdbSymUid(func.GetID()).asCompilandSym();1601// After we iterate through inline sites inside the function, we already get1602// all the info needed, removing from the map to save memory.1603std::set<uint64_t> remove_uids;1604auto parse_blocks = [&](SymbolKind kind, PdbCompilandSymId id) {1605if (kind == S_GPROC32 || kind == S_LPROC32 || kind == S_BLOCK32 ||1606kind == S_INLINESITE) {1607GetOrCreateBlock(id);1608if (kind == S_INLINESITE)1609remove_uids.insert(toOpaqueUid(id));1610return true;1611}1612return false;1613};1614size_t count = ParseSymbolArrayInScope(func_id, parse_blocks);1615for (uint64_t uid : remove_uids) {1616m_inline_sites.erase(uid);1617}1618return count;1619}16201621size_t SymbolFileNativePDB::ParseSymbolArrayInScope(1622PdbCompilandSymId parent_id,1623llvm::function_ref<bool(SymbolKind, PdbCompilandSymId)> fn) {1624CompilandIndexItem *cii = m_index->compilands().GetCompiland(parent_id.modi);1625CVSymbolArray syms =1626cii->m_debug_stream.getSymbolArrayForScope(parent_id.offset);16271628size_t count = 1;1629for (auto iter = syms.begin(); iter != syms.end(); ++iter) {1630PdbCompilandSymId child_id(parent_id.modi, iter.offset());1631if (fn(iter->kind(), child_id))1632++count;1633}16341635return count;1636}16371638void SymbolFileNativePDB::DumpClangAST(Stream &s) {1639auto ts_or_err = GetTypeSystemForLanguage(eLanguageTypeC_plus_plus);1640if (!ts_or_err)1641return;1642auto ts = *ts_or_err;1643TypeSystemClang *clang = llvm::dyn_cast_or_null<TypeSystemClang>(ts.get());1644if (!clang)1645return;1646clang->GetNativePDBParser()->Dump(s);1647}16481649void SymbolFileNativePDB::FindGlobalVariables(1650ConstString name, const CompilerDeclContext &parent_decl_ctx,1651uint32_t max_matches, VariableList &variables) {1652std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());1653using SymbolAndOffset = std::pair<uint32_t, llvm::codeview::CVSymbol>;16541655std::vector<SymbolAndOffset> results = m_index->globals().findRecordsByName(1656name.GetStringRef(), m_index->symrecords());1657for (const SymbolAndOffset &result : results) {1658switch (result.second.kind()) {1659case SymbolKind::S_GDATA32:1660case SymbolKind::S_LDATA32:1661case SymbolKind::S_GTHREAD32:1662case SymbolKind::S_LTHREAD32:1663case SymbolKind::S_CONSTANT: {1664PdbGlobalSymId global(result.first, false);1665if (VariableSP var = GetOrCreateGlobalVariable(global))1666variables.AddVariable(var);1667break;1668}1669default:1670continue;1671}1672}1673}16741675void SymbolFileNativePDB::FindFunctions(1676const Module::LookupInfo &lookup_info,1677const CompilerDeclContext &parent_decl_ctx, bool include_inlines,1678SymbolContextList &sc_list) {1679std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());1680ConstString name = lookup_info.GetLookupName();1681FunctionNameType name_type_mask = lookup_info.GetNameTypeMask();1682if (name_type_mask & eFunctionNameTypeFull)1683name = lookup_info.GetName();16841685// For now we only support lookup by method name or full name.1686if (!(name_type_mask & eFunctionNameTypeFull ||1687name_type_mask & eFunctionNameTypeMethod))1688return;16891690using SymbolAndOffset = std::pair<uint32_t, llvm::codeview::CVSymbol>;16911692std::vector<SymbolAndOffset> matches = m_index->globals().findRecordsByName(1693name.GetStringRef(), m_index->symrecords());1694for (const SymbolAndOffset &match : matches) {1695if (match.second.kind() != S_PROCREF && match.second.kind() != S_LPROCREF)1696continue;1697ProcRefSym proc(match.second.kind());1698cantFail(SymbolDeserializer::deserializeAs<ProcRefSym>(match.second, proc));16991700if (!IsValidRecord(proc))1701continue;17021703CompilandIndexItem &cci =1704m_index->compilands().GetOrCreateCompiland(proc.modi());1705SymbolContext sc;17061707sc.comp_unit = GetOrCreateCompileUnit(cci).get();1708PdbCompilandSymId func_id(proc.modi(), proc.SymOffset);1709sc.function = GetOrCreateFunction(func_id, *sc.comp_unit).get();17101711sc_list.Append(sc);1712}1713}17141715void SymbolFileNativePDB::FindFunctions(const RegularExpression ®ex,1716bool include_inlines,1717SymbolContextList &sc_list) {}17181719void SymbolFileNativePDB::FindTypes(const lldb_private::TypeQuery &query,1720lldb_private::TypeResults &results) {17211722// Make sure we haven't already searched this SymbolFile before.1723if (results.AlreadySearched(this))1724return;17251726std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());17271728std::vector<TypeIndex> matches =1729m_index->tpi().findRecordsByName(query.GetTypeBasename().GetStringRef());17301731for (TypeIndex type_idx : matches) {1732TypeSP type_sp = GetOrCreateType(type_idx);1733if (!type_sp)1734continue;17351736// We resolved a type. Get the fully qualified name to ensure it matches.1737ConstString name = type_sp->GetQualifiedName();1738TypeQuery type_match(name.GetStringRef(), TypeQueryOptions::e_exact_match);1739if (query.ContextMatches(type_match.GetContextRef())) {1740results.InsertUnique(type_sp);1741if (results.Done(query))1742return;1743}1744}1745}17461747void SymbolFileNativePDB::FindTypesByName(llvm::StringRef name,1748uint32_t max_matches,1749TypeMap &types) {17501751std::vector<TypeIndex> matches = m_index->tpi().findRecordsByName(name);1752if (max_matches > 0 && max_matches < matches.size())1753matches.resize(max_matches);17541755for (TypeIndex ti : matches) {1756TypeSP type = GetOrCreateType(ti);1757if (!type)1758continue;17591760types.Insert(type);1761}1762}17631764size_t SymbolFileNativePDB::ParseTypes(CompileUnit &comp_unit) {1765std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());1766// Only do the full type scan the first time.1767if (m_done_full_type_scan)1768return 0;17691770const size_t old_count = GetTypeList().GetSize();1771LazyRandomTypeCollection &types = m_index->tpi().typeCollection();17721773// First process the entire TPI stream.1774for (auto ti = types.getFirst(); ti; ti = types.getNext(*ti)) {1775TypeSP type = GetOrCreateType(*ti);1776if (type)1777(void)type->GetFullCompilerType();1778}17791780// Next look for S_UDT records in the globals stream.1781for (const uint32_t gid : m_index->globals().getGlobalsTable()) {1782PdbGlobalSymId global{gid, false};1783CVSymbol sym = m_index->ReadSymbolRecord(global);1784if (sym.kind() != S_UDT)1785continue;17861787UDTSym udt = llvm::cantFail(SymbolDeserializer::deserializeAs<UDTSym>(sym));1788bool is_typedef = true;1789if (IsTagRecord(PdbTypeSymId{udt.Type, false}, m_index->tpi())) {1790CVType cvt = m_index->tpi().getType(udt.Type);1791llvm::StringRef name = CVTagRecord::create(cvt).name();1792if (name == udt.Name)1793is_typedef = false;1794}17951796if (is_typedef)1797GetOrCreateTypedef(global);1798}17991800const size_t new_count = GetTypeList().GetSize();18011802m_done_full_type_scan = true;18031804return new_count - old_count;1805}18061807size_t1808SymbolFileNativePDB::ParseVariablesForCompileUnit(CompileUnit &comp_unit,1809VariableList &variables) {1810PdbSymUid sym_uid(comp_unit.GetID());1811lldbassert(sym_uid.kind() == PdbSymUidKind::Compiland);1812return 0;1813}18141815VariableSP SymbolFileNativePDB::CreateLocalVariable(PdbCompilandSymId scope_id,1816PdbCompilandSymId var_id,1817bool is_param) {1818ModuleSP module = GetObjectFile()->GetModule();1819Block &block = GetOrCreateBlock(scope_id);1820// Get function block.1821Block *func_block = █1822while (func_block->GetParent()) {1823func_block = func_block->GetParent();1824}1825Address addr;1826func_block->GetStartAddress(addr);1827VariableInfo var_info =1828GetVariableLocationInfo(*m_index, var_id, *func_block, module);1829Function *func = func_block->CalculateSymbolContextFunction();1830if (!func)1831return nullptr;1832// Use empty dwarf expr if optimized away so that it won't be filtered out1833// when lookuping local variables in this scope.1834if (!var_info.location.IsValid())1835var_info.location = DWARFExpressionList(module, DWARFExpression(), nullptr);1836var_info.location.SetFuncFileAddress(1837func->GetAddressRange().GetBaseAddress().GetFileAddress());1838CompilandIndexItem *cii = m_index->compilands().GetCompiland(var_id.modi);1839CompUnitSP comp_unit_sp = GetOrCreateCompileUnit(*cii);1840TypeSP type_sp = GetOrCreateType(var_info.type);1841if (!type_sp)1842return nullptr;1843std::string name = var_info.name.str();1844Declaration decl;1845SymbolFileTypeSP sftype =1846std::make_shared<SymbolFileType>(*this, type_sp->GetID());18471848is_param |= var_info.is_param;1849ValueType var_scope =1850is_param ? eValueTypeVariableArgument : eValueTypeVariableLocal;1851bool external = false;1852bool artificial = false;1853bool location_is_constant_data = false;1854bool static_member = false;1855Variable::RangeList scope_ranges;1856VariableSP var_sp = std::make_shared<Variable>(1857toOpaqueUid(var_id), name.c_str(), name.c_str(), sftype, var_scope,1858&block, scope_ranges, &decl, var_info.location, external, artificial,1859location_is_constant_data, static_member);1860if (!is_param) {1861auto ts_or_err = GetTypeSystemForLanguage(comp_unit_sp->GetLanguage());1862if (auto err = ts_or_err.takeError())1863return nullptr;1864auto ts = *ts_or_err;1865if (!ts)1866return nullptr;18671868ts->GetNativePDBParser()->GetOrCreateVariableDecl(scope_id, var_id);1869}1870m_local_variables[toOpaqueUid(var_id)] = var_sp;1871return var_sp;1872}18731874VariableSP SymbolFileNativePDB::GetOrCreateLocalVariable(1875PdbCompilandSymId scope_id, PdbCompilandSymId var_id, bool is_param) {1876auto iter = m_local_variables.find(toOpaqueUid(var_id));1877if (iter != m_local_variables.end())1878return iter->second;18791880return CreateLocalVariable(scope_id, var_id, is_param);1881}18821883TypeSP SymbolFileNativePDB::CreateTypedef(PdbGlobalSymId id) {1884CVSymbol sym = m_index->ReadSymbolRecord(id);1885lldbassert(sym.kind() == SymbolKind::S_UDT);18861887UDTSym udt = llvm::cantFail(SymbolDeserializer::deserializeAs<UDTSym>(sym));18881889TypeSP target_type = GetOrCreateType(udt.Type);18901891auto ts_or_err = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);1892if (auto err = ts_or_err.takeError())1893return nullptr;1894auto ts = *ts_or_err;1895if (!ts)1896return nullptr;18971898ts->GetNativePDBParser()->GetOrCreateTypedefDecl(id);18991900Declaration decl;1901return MakeType(1902toOpaqueUid(id), ConstString(udt.Name), target_type->GetByteSize(nullptr),1903nullptr, target_type->GetID(), lldb_private::Type::eEncodingIsTypedefUID,1904decl, target_type->GetForwardCompilerType(),1905lldb_private::Type::ResolveState::Forward);1906}19071908TypeSP SymbolFileNativePDB::GetOrCreateTypedef(PdbGlobalSymId id) {1909auto iter = m_types.find(toOpaqueUid(id));1910if (iter != m_types.end())1911return iter->second;19121913return CreateTypedef(id);1914}19151916size_t SymbolFileNativePDB::ParseVariablesForBlock(PdbCompilandSymId block_id) {1917Block &block = GetOrCreateBlock(block_id);19181919size_t count = 0;19201921CompilandIndexItem *cii = m_index->compilands().GetCompiland(block_id.modi);1922CVSymbol sym = cii->m_debug_stream.readSymbolAtOffset(block_id.offset);1923uint32_t params_remaining = 0;1924switch (sym.kind()) {1925case S_GPROC32:1926case S_LPROC32: {1927ProcSym proc(static_cast<SymbolRecordKind>(sym.kind()));1928cantFail(SymbolDeserializer::deserializeAs<ProcSym>(sym, proc));1929CVType signature = m_index->tpi().getType(proc.FunctionType);1930if (signature.kind() == LF_PROCEDURE) {1931ProcedureRecord sig;1932if (llvm::Error e = TypeDeserializer::deserializeAs<ProcedureRecord>(1933signature, sig)) {1934llvm::consumeError(std::move(e));1935return 0;1936}1937params_remaining = sig.getParameterCount();1938} else if (signature.kind() == LF_MFUNCTION) {1939MemberFunctionRecord sig;1940if (llvm::Error e = TypeDeserializer::deserializeAs<MemberFunctionRecord>(1941signature, sig)) {1942llvm::consumeError(std::move(e));1943return 0;1944}1945params_remaining = sig.getParameterCount();1946} else1947return 0;1948break;1949}1950case S_BLOCK32:1951break;1952case S_INLINESITE:1953break;1954default:1955lldbassert(false && "Symbol is not a block!");1956return 0;1957}19581959VariableListSP variables = block.GetBlockVariableList(false);1960if (!variables) {1961variables = std::make_shared<VariableList>();1962block.SetVariableList(variables);1963}19641965CVSymbolArray syms = limitSymbolArrayToScope(1966cii->m_debug_stream.getSymbolArray(), block_id.offset);19671968// Skip the first record since it's a PROC32 or BLOCK32, and there's1969// no point examining it since we know it's not a local variable.1970syms.drop_front();1971auto iter = syms.begin();1972auto end = syms.end();19731974while (iter != end) {1975uint32_t record_offset = iter.offset();1976CVSymbol variable_cvs = *iter;1977PdbCompilandSymId child_sym_id(block_id.modi, record_offset);1978++iter;19791980// If this is a block or inline site, recurse into its children and then1981// skip it.1982if (variable_cvs.kind() == S_BLOCK32 ||1983variable_cvs.kind() == S_INLINESITE) {1984uint32_t block_end = getScopeEndOffset(variable_cvs);1985count += ParseVariablesForBlock(child_sym_id);1986iter = syms.at(block_end);1987continue;1988}19891990bool is_param = params_remaining > 0;1991VariableSP variable;1992switch (variable_cvs.kind()) {1993case S_REGREL32:1994case S_REGISTER:1995case S_LOCAL:1996variable = GetOrCreateLocalVariable(block_id, child_sym_id, is_param);1997if (is_param)1998--params_remaining;1999if (variable)2000variables->AddVariableIfUnique(variable);2001break;2002default:2003break;2004}2005}20062007// Pass false for set_children, since we call this recursively so that the2008// children will call this for themselves.2009block.SetDidParseVariables(true, false);20102011return count;2012}20132014size_t SymbolFileNativePDB::ParseVariablesForContext(const SymbolContext &sc) {2015std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());2016lldbassert(sc.function || sc.comp_unit);20172018VariableListSP variables;2019if (sc.block) {2020PdbSymUid block_id(sc.block->GetID());20212022size_t count = ParseVariablesForBlock(block_id.asCompilandSym());2023return count;2024}20252026if (sc.function) {2027PdbSymUid block_id(sc.function->GetID());20282029size_t count = ParseVariablesForBlock(block_id.asCompilandSym());2030return count;2031}20322033if (sc.comp_unit) {2034variables = sc.comp_unit->GetVariableList(false);2035if (!variables) {2036variables = std::make_shared<VariableList>();2037sc.comp_unit->SetVariableList(variables);2038}2039return ParseVariablesForCompileUnit(*sc.comp_unit, *variables);2040}20412042llvm_unreachable("Unreachable!");2043}20442045CompilerDecl SymbolFileNativePDB::GetDeclForUID(lldb::user_id_t uid) {2046auto ts_or_err = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);2047if (auto err = ts_or_err.takeError())2048return CompilerDecl();2049auto ts = *ts_or_err;2050if (!ts)2051return {};20522053if (auto decl = ts->GetNativePDBParser()->GetOrCreateDeclForUid(uid))2054return *decl;2055return CompilerDecl();2056}20572058CompilerDeclContext2059SymbolFileNativePDB::GetDeclContextForUID(lldb::user_id_t uid) {2060auto ts_or_err = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);2061if (auto err = ts_or_err.takeError())2062return {};2063auto ts = *ts_or_err;2064if (!ts)2065return {};20662067PdbAstBuilder *ast_builder = ts->GetNativePDBParser();2068clang::DeclContext *context =2069ast_builder->GetOrCreateDeclContextForUid(PdbSymUid(uid));2070if (!context)2071return {};20722073return ast_builder->ToCompilerDeclContext(*context);2074}20752076CompilerDeclContext2077SymbolFileNativePDB::GetDeclContextContainingUID(lldb::user_id_t uid) {2078auto ts_or_err = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);2079if (auto err = ts_or_err.takeError())2080return CompilerDeclContext();2081auto ts = *ts_or_err;2082if (!ts)2083return {};20842085PdbAstBuilder *ast_builder = ts->GetNativePDBParser();2086clang::DeclContext *context = ast_builder->GetParentDeclContext(PdbSymUid(uid));2087if (!context)2088return CompilerDeclContext();2089return ast_builder->ToCompilerDeclContext(*context);2090}20912092Type *SymbolFileNativePDB::ResolveTypeUID(lldb::user_id_t type_uid) {2093std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());2094auto iter = m_types.find(type_uid);2095// lldb should not be passing us non-sensical type uids. the only way it2096// could have a type uid in the first place is if we handed it out, in which2097// case we should know about the type. However, that doesn't mean we've2098// instantiated it yet. We can vend out a UID for a future type. So if the2099// type doesn't exist, let's instantiate it now.2100if (iter != m_types.end())2101return &*iter->second;21022103PdbSymUid uid(type_uid);2104lldbassert(uid.kind() == PdbSymUidKind::Type);2105PdbTypeSymId type_id = uid.asTypeSym();2106if (type_id.index.isNoneType())2107return nullptr;21082109TypeSP type_sp = CreateAndCacheType(type_id);2110if (!type_sp)2111return nullptr;2112return &*type_sp;2113}21142115std::optional<SymbolFile::ArrayInfo>2116SymbolFileNativePDB::GetDynamicArrayInfoForUID(2117lldb::user_id_t type_uid, const lldb_private::ExecutionContext *exe_ctx) {2118return std::nullopt;2119}21202121bool SymbolFileNativePDB::CompleteType(CompilerType &compiler_type) {2122std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());2123auto ts = compiler_type.GetTypeSystem();2124auto clang_type_system = ts.dyn_cast_or_null<TypeSystemClang>();2125if (!clang_type_system)2126return false;21272128PdbAstBuilder *ast_builder =2129static_cast<PdbAstBuilder *>(clang_type_system->GetNativePDBParser());2130if (ast_builder &&2131ast_builder->GetClangASTImporter().CanImport(compiler_type))2132return ast_builder->GetClangASTImporter().CompleteType(compiler_type);2133clang::QualType qt =2134clang::QualType::getFromOpaquePtr(compiler_type.GetOpaqueQualType());21352136return ast_builder->CompleteType(qt);2137}21382139void SymbolFileNativePDB::GetTypes(lldb_private::SymbolContextScope *sc_scope,2140TypeClass type_mask,2141lldb_private::TypeList &type_list) {}21422143CompilerDeclContext SymbolFileNativePDB::FindNamespace(2144ConstString name, const CompilerDeclContext &parent_decl_ctx, bool) {2145return {};2146}21472148llvm::Expected<lldb::TypeSystemSP>2149SymbolFileNativePDB::GetTypeSystemForLanguage(lldb::LanguageType language) {2150auto type_system_or_err =2151m_objfile_sp->GetModule()->GetTypeSystemForLanguage(language);2152if (type_system_or_err)2153if (auto ts = *type_system_or_err)2154ts->SetSymbolFile(this);2155return type_system_or_err;2156}21572158uint64_t SymbolFileNativePDB::GetDebugInfoSize(bool load_all_debug_info) {2159// PDB files are a separate file that contains all debug info.2160return m_index->pdb().getFileSize();2161}21622163void SymbolFileNativePDB::BuildParentMap() {2164LazyRandomTypeCollection &types = m_index->tpi().typeCollection();21652166llvm::DenseMap<TypeIndex, TypeIndex> forward_to_full;2167llvm::DenseMap<TypeIndex, TypeIndex> full_to_forward;21682169struct RecordIndices {2170TypeIndex forward;2171TypeIndex full;2172};21732174llvm::StringMap<RecordIndices> record_indices;21752176for (auto ti = types.getFirst(); ti; ti = types.getNext(*ti)) {2177CVType type = types.getType(*ti);2178if (!IsTagRecord(type))2179continue;21802181CVTagRecord tag = CVTagRecord::create(type);21822183RecordIndices &indices = record_indices[tag.asTag().getUniqueName()];2184if (tag.asTag().isForwardRef())2185indices.forward = *ti;2186else2187indices.full = *ti;21882189if (indices.full != TypeIndex::None() &&2190indices.forward != TypeIndex::None()) {2191forward_to_full[indices.forward] = indices.full;2192full_to_forward[indices.full] = indices.forward;2193}21942195// We're looking for LF_NESTTYPE records in the field list, so ignore2196// forward references (no field list), and anything without a nested class2197// (since there won't be any LF_NESTTYPE records).2198if (tag.asTag().isForwardRef() || !tag.asTag().containsNestedClass())2199continue;22002201struct ProcessTpiStream : public TypeVisitorCallbacks {2202ProcessTpiStream(PdbIndex &index, TypeIndex parent,2203const CVTagRecord &parent_cvt,2204llvm::DenseMap<TypeIndex, TypeIndex> &parents)2205: index(index), parents(parents), parent(parent),2206parent_cvt(parent_cvt) {}22072208PdbIndex &index;2209llvm::DenseMap<TypeIndex, TypeIndex> &parents;22102211unsigned unnamed_type_index = 1;2212TypeIndex parent;2213const CVTagRecord &parent_cvt;22142215llvm::Error visitKnownMember(CVMemberRecord &CVR,2216NestedTypeRecord &Record) override {2217std::string unnamed_type_name;2218if (Record.Name.empty()) {2219unnamed_type_name =2220llvm::formatv("<unnamed-type-$S{0}>", unnamed_type_index).str();2221Record.Name = unnamed_type_name;2222++unnamed_type_index;2223}2224std::optional<CVTagRecord> tag =2225GetNestedTagDefinition(Record, parent_cvt, index.tpi());2226if (!tag)2227return llvm::ErrorSuccess();22282229parents[Record.Type] = parent;2230return llvm::ErrorSuccess();2231}2232};22332234CVType field_list_cvt = m_index->tpi().getType(tag.asTag().FieldList);2235ProcessTpiStream process(*m_index, *ti, tag, m_parent_types);2236FieldListRecord field_list;2237if (llvm::Error error = TypeDeserializer::deserializeAs<FieldListRecord>(2238field_list_cvt, field_list))2239llvm::consumeError(std::move(error));2240if (llvm::Error error = visitMemberRecordStream(field_list.Data, process))2241llvm::consumeError(std::move(error));2242}22432244// Now that we know the forward -> full mapping of all type indices, we can2245// re-write all the indices. At the end of this process, we want a mapping2246// consisting of fwd -> full and full -> full for all child -> parent indices.2247// We can re-write the values in place, but for the keys, we must save them2248// off so that we don't modify the map in place while also iterating it.2249std::vector<TypeIndex> full_keys;2250std::vector<TypeIndex> fwd_keys;2251for (auto &entry : m_parent_types) {2252TypeIndex key = entry.first;2253TypeIndex value = entry.second;22542255auto iter = forward_to_full.find(value);2256if (iter != forward_to_full.end())2257entry.second = iter->second;22582259iter = forward_to_full.find(key);2260if (iter != forward_to_full.end())2261fwd_keys.push_back(key);2262else2263full_keys.push_back(key);2264}2265for (TypeIndex fwd : fwd_keys) {2266TypeIndex full = forward_to_full[fwd];2267TypeIndex parent_idx = m_parent_types[fwd];2268m_parent_types[full] = parent_idx;2269}2270for (TypeIndex full : full_keys) {2271TypeIndex fwd = full_to_forward[full];2272m_parent_types[fwd] = m_parent_types[full];2273}2274}22752276std::optional<PdbCompilandSymId>2277SymbolFileNativePDB::FindSymbolScope(PdbCompilandSymId id) {2278CVSymbol sym = m_index->ReadSymbolRecord(id);2279if (symbolOpensScope(sym.kind())) {2280// If this exact symbol opens a scope, we can just directly access its2281// parent.2282id.offset = getScopeParentOffset(sym);2283// Global symbols have parent offset of 0. Return std::nullopt to indicate2284// this.2285if (id.offset == 0)2286return std::nullopt;2287return id;2288}22892290// Otherwise we need to start at the beginning and iterate forward until we2291// reach (or pass) this particular symbol2292CompilandIndexItem &cii = m_index->compilands().GetOrCreateCompiland(id.modi);2293const CVSymbolArray &syms = cii.m_debug_stream.getSymbolArray();22942295auto begin = syms.begin();2296auto end = syms.at(id.offset);2297std::vector<PdbCompilandSymId> scope_stack;22982299while (begin != end) {2300if (begin.offset() > id.offset) {2301// We passed it. We couldn't even find this symbol record.2302lldbassert(false && "Invalid compiland symbol id!");2303return std::nullopt;2304}23052306// We haven't found the symbol yet. Check if we need to open or close the2307// scope stack.2308if (symbolOpensScope(begin->kind())) {2309// We can use the end offset of the scope to determine whether or not2310// we can just outright skip this entire scope.2311uint32_t scope_end = getScopeEndOffset(*begin);2312if (scope_end < id.offset) {2313begin = syms.at(scope_end);2314} else {2315// The symbol we're looking for is somewhere in this scope.2316scope_stack.emplace_back(id.modi, begin.offset());2317}2318} else if (symbolEndsScope(begin->kind())) {2319scope_stack.pop_back();2320}2321++begin;2322}2323if (scope_stack.empty())2324return std::nullopt;2325// We have a match! Return the top of the stack2326return scope_stack.back();2327}23282329std::optional<llvm::codeview::TypeIndex>2330SymbolFileNativePDB::GetParentType(llvm::codeview::TypeIndex ti) {2331auto parent_iter = m_parent_types.find(ti);2332if (parent_iter == m_parent_types.end())2333return std::nullopt;2334return parent_iter->second;2335}233623372338