Index: include/lldb/Symbol/ClangASTContext.h =================================================================== --- include/lldb/Symbol/ClangASTContext.h +++ include/lldb/Symbol/ClangASTContext.h @@ -37,6 +37,7 @@ #include "lldb/lldb-enumerations.h" class DWARFASTParserClang; +class PDBASTParser; namespace lldb_private { @@ -524,6 +525,8 @@ //------------------------------------------------------------------ DWARFASTParser * GetDWARFParser() override; + PDBASTParser * + GetPDBParser(); //------------------------------------------------------------------ // ClangASTContext callbacks for external source lookups. @@ -1189,6 +1192,7 @@ std::unique_ptr m_selector_table_ap; std::unique_ptr m_builtins_ap; std::unique_ptr m_dwarf_ast_parser_ap; + std::unique_ptr m_pdb_ast_parser_ap; std::unique_ptr m_scratch_ast_source_ap; std::unique_ptr m_mangle_ctx_ap; CompleteTagDeclCallback m_callback_tag_decl; Index: source/Plugins/SymbolFile/PDB/CMakeLists.txt =================================================================== --- source/Plugins/SymbolFile/PDB/CMakeLists.txt +++ source/Plugins/SymbolFile/PDB/CMakeLists.txt @@ -2,5 +2,6 @@ DebugInfoPDB) add_lldb_library(lldbPluginSymbolFilePDB + PDBASTParser.cpp SymbolFilePDB.cpp ) Index: source/Plugins/SymbolFile/PDB/PDBASTParser.h =================================================================== --- /dev/null +++ source/Plugins/SymbolFile/PDB/PDBASTParser.h @@ -0,0 +1,62 @@ +//===-- PDBASTParser.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_PDB_PDBASTPARSER_H +#define LLDB_PLUGINS_SYMBOLFILE_PDB_PDBASTPARSER_H + +#include "lldb/lldb-forward.h" + +#include "lldb/Symbol/ClangASTImporter.h" + +namespace clang +{ +class CharUnits; +class CXXRecordDecl; +class FieldDecl; +class RecordDecl; +} + +namespace lldb_private +{ +class ClangASTContext; +} + +namespace llvm +{ +class PDBSymbol; +} + +class PDBASTParser +{ +public: + PDBASTParser(lldb_private::ClangASTContext &ast); + ~PDBASTParser(); + + // DebugInfoASTParser interface + bool + CanCompleteType(const lldb_private::CompilerType &compiler_type); + + bool + CompleteType(const lldb_private::CompilerType &compiler_type); + + bool + LayoutRecordType(const clang::RecordDecl *record_decl, uint64_t &bit_size, uint64_t &alignment, + llvm::DenseMap &field_offsets, + llvm::DenseMap &base_offsets, + llvm::DenseMap &vbase_offsets); + + lldb::TypeSP + CreateLLDBTypeFromPDBType(const llvm::PDBSymbol &type); + +private: + lldb_private::ClangASTContext &m_ast; + lldb_private::ClangASTImporter m_ast_importer; +}; + +#endif // SymbolFileDWARF_DWARFASTParserClang_h_ Index: source/Plugins/SymbolFile/PDB/PDBASTParser.cpp =================================================================== --- /dev/null +++ source/Plugins/SymbolFile/PDB/PDBASTParser.cpp @@ -0,0 +1,247 @@ +//===-- PDBASTParser.cpp ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PDBASTParser.h" + +#include "clang/AST/CharUnits.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" + +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/Declaration.h" +#include "lldb/Symbol/SymbolFile.h" +#include "lldb/Symbol/TypeSystem.h" + +#include "llvm/DebugInfo/PDB/PDBSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" + +using namespace lldb; +using namespace lldb_private; +using namespace llvm; + +namespace +{ +int +TranslateUdtKind(PDB_UdtType pdb_kind) +{ + switch (pdb_kind) + { + case PDB_UdtType::Class: + return clang::TTK_Class; + case PDB_UdtType::Struct: + return clang::TTK_Struct; + case PDB_UdtType::Union: + return clang::TTK_Union; + case PDB_UdtType::Interface: + return clang::TTK_Interface; + } + return clang::TTK_Class; +} +lldb::Encoding +TranslateBuiltinEncoding(PDB_BuiltinType type) +{ + switch (type) + { + case PDB_BuiltinType::Float: + return lldb::eEncodingIEEE754; + case PDB_BuiltinType::Int: + case PDB_BuiltinType::Long: + case PDB_BuiltinType::Char: + return lldb::eEncodingSint; + case PDB_BuiltinType::Bool: + case PDB_BuiltinType::UInt: + case PDB_BuiltinType::ULong: + case PDB_BuiltinType::HResult: + return lldb::eEncodingUint; + default: + return lldb::eEncodingInvalid; + } +} +llvm::StringRef +GetBuiltinTypeName(const PDBSymbolTypeBuiltin &type) +{ + switch (type.getBuiltinType()) + { + case PDB_BuiltinType::Float: + if (type.getLength() == 4) + return "float"; + if (type.getLength() == 8) + return "double"; + break; + case PDB_BuiltinType::Int: + if (type.getLength() == 2) + return "short"; + if (type.getLength() == 4) + return "int"; + if (type.getLength() == 8) + return "__int64"; + break; + case PDB_BuiltinType::Long: + if (type.getLength() == 4) + return "long"; + if (type.getLength() == 8) + return "long long"; + break; + case PDB_BuiltinType::Char: + return "char"; + case PDB_BuiltinType::WCharT: + return "wchar_t"; + case PDB_BuiltinType::Bool: + return "bool"; + case PDB_BuiltinType::UInt: + if (type.getLength() == 2) + return "unsigned short"; + if (type.getLength() == 4) + return "unsigned int"; + if (type.getLength() == 8) + return "unsigned __int64"; + break; + case PDB_BuiltinType::ULong: + if (type.getLength() == 4) + return "unsigned long"; + if (type.getLength() == 8) + return "unsigned long long"; + break; + case PDB_BuiltinType::HResult: + return "HRESULT"; + default: + return llvm::StringRef(); + } + return llvm::StringRef(); +} +} + +PDBASTParser::PDBASTParser(lldb_private::ClangASTContext &ast) : m_ast(ast) +{ +} + +PDBASTParser::~PDBASTParser() +{ +} + +// DebugInfoASTParser interface + +lldb::TypeSP +PDBASTParser::CreateLLDBTypeFromPDBType(const llvm::PDBSymbol &type) +{ + // PDB doesn't maintain enough information to robustly rebuild the entire + // tree, and this is most problematic when it comes to figure out the + // right DeclContext to put a type in. So for now, everything goes in + // the translation unit decl as a fully qualified type. + clang::DeclContext *tu_decl_ctx = m_ast.GetTranslationUnitDecl(); + Declaration decl; + + if (auto udt = llvm::dyn_cast(&type)) + { + AccessType access = lldb::eAccessPublic; + PDB_UdtType udt_kind = udt->getUdtKind(); + + if (udt_kind == PDB_UdtType::Class) + access = lldb::eAccessPrivate; + + CompilerType clang_type = + m_ast.CreateRecordType(tu_decl_ctx, access, udt->getName().c_str(), TranslateUdtKind(udt_kind), + lldb::eLanguageTypeC_plus_plus, nullptr); + + return std::make_shared(type.getSymIndexId(), m_ast.GetSymbolFile(), ConstString(udt->getName()), + udt->getLength(), nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID, decl, + clang_type, Type::eResolveStateFull); + } + else if (auto base = llvm::dyn_cast(&type)) + { + uint64_t bytes = base->getLength(); + lldb::Encoding encoding = TranslateBuiltinEncoding(base->getBuiltinType()); + + CompilerType builtin_type = m_ast.GetBuiltinTypeForEncodingAndBitSize(encoding, bytes * 8); + if (!builtin_type.IsValid()) + return nullptr; + + llvm::StringRef name = GetBuiltinTypeName(*base); + return std::make_shared(type.getSymIndexId(), m_ast.GetSymbolFile(), ConstString(name), bytes, nullptr, + LLDB_INVALID_UID, Type::eEncodingIsUID, decl, builtin_type, + Type::eResolveStateFull); + } + else if (auto enum_type = llvm::dyn_cast(&type)) + { + std::string name = enum_type->getName(); + lldb::Encoding encoding = TranslateBuiltinEncoding(enum_type->getBuiltinType()); + uint64_t bytes = enum_type->getLength(); + CompilerType builtin_type = m_ast.GetBuiltinTypeForEncodingAndBitSize(encoding, bytes * 8); + + CompilerType ast_enum = m_ast.CreateEnumerationType(name.c_str(), tu_decl_ctx, decl, builtin_type); + return std::make_shared(type.getSymIndexId(), m_ast.GetSymbolFile(), ConstString(name), bytes, nullptr, + LLDB_INVALID_UID, Type::eEncodingIsUID, decl, ast_enum, Type::eResolveStateFull); + } + else if (auto type_def = llvm::dyn_cast(&type)) + { + Type *target_type = m_ast.GetSymbolFile()->ResolveTypeUID(type_def->getTypeId()); + std::string name = type_def->getName(); + uint64_t bytes = type_def->getLength(); + if (!target_type) + return nullptr; + CompilerType target_ast_type = target_type->GetFullCompilerType(); + CompilerDeclContext target_decl_ctx = m_ast.GetSymbolFile()->GetDeclContextForUID(target_type->GetID()); + CompilerType ast_typedef = m_ast.CreateTypedefType(target_ast_type, name.c_str(), target_decl_ctx); + return std::make_shared(type_def->getSymIndexId(), m_ast.GetSymbolFile(), ConstString(name), bytes, + nullptr, target_type->GetID(), Type::eEncodingIsTypedefUID, decl, ast_typedef, + Type::eResolveStateFull); + } + else if (auto func_sig = llvm::dyn_cast(&type)) + { + auto arg_enum = func_sig->getArguments(); + uint32_t num_args = arg_enum->getChildCount(); + std::vector arg_list(num_args); + while (auto arg = arg_enum->getNext()) + { + Type *arg_type = m_ast.GetSymbolFile()->ResolveTypeUID(arg->getSymIndexId()); + // If there's some error looking up one of the dependent types of this function signature, bail. + if (!arg_type) + return nullptr; + CompilerType arg_ast_type = arg_type->GetFullCompilerType(); + arg_list.push_back(arg_ast_type); + } + auto pdb_return_type = func_sig->getReturnType(); + Type *return_type = m_ast.GetSymbolFile()->ResolveTypeUID(pdb_return_type->getSymIndexId()); + // If there's some error looking up one of the dependent types of this function signature, bail. + if (!return_type) + return nullptr; + CompilerType return_ast_type = return_type->GetFullCompilerType(); + uint32_t type_quals = 0; + if (func_sig->isConstType()) + type_quals |= clang::Qualifiers::Const; + if (func_sig->isVolatileType()) + type_quals |= clang::Qualifiers::Volatile; + CompilerType func_sig_ast_type = + m_ast.CreateFunctionType(return_ast_type, &arg_list[0], num_args, false, type_quals); + + return std::make_shared(func_sig->getSymIndexId(), m_ast.GetSymbolFile(), ConstString(), 0, nullptr, + LLDB_INVALID_UID, Type::eEncodingIsUID, decl, func_sig_ast_type, + Type::eResolveStateFull); + } + else if (auto array_type = llvm::dyn_cast(&type)) + { + uint32_t num_elements = array_type->getCount(); + uint32_t element_uid = array_type->getElementType()->getSymIndexId(); + uint32_t bytes = array_type->getLength(); + + Type *element_type = m_ast.GetSymbolFile()->ResolveTypeUID(element_uid); + CompilerType element_ast_type = element_type->GetFullCompilerType(); + CompilerType array_ast_type = m_ast.CreateArrayType(element_ast_type, num_elements, false); + return std::make_shared(array_type->getSymIndexId(), m_ast.GetSymbolFile(), ConstString(), bytes, nullptr, + LLDB_INVALID_UID, Type::eEncodingIsUID, decl, array_ast_type, + Type::eResolveStateFull); + } + return nullptr; +} Index: source/Plugins/SymbolFile/PDB/SymbolFilePDB.h =================================================================== --- source/Plugins/SymbolFile/PDB/SymbolFilePDB.h +++ source/Plugins/SymbolFile/PDB/SymbolFilePDB.h @@ -10,11 +10,10 @@ #ifndef lldb_Plugins_SymbolFile_PDB_SymbolFilePDB_h_ #define lldb_Plugins_SymbolFile_PDB_SymbolFilePDB_h_ -#include - #include "lldb/Core/UserID.h" #include "lldb/Symbol/SymbolFile.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/DebugInfo/PDB/IPDBSession.h" #include "llvm/DebugInfo/PDB/PDB.h" @@ -179,12 +178,14 @@ void BuildSupportFileIdToSupportFileIndexMap(const llvm::PDBSymbolCompiland &cu, - std::unordered_map &index_map) const; + llvm::DenseMap &index_map) const; - std::unordered_map m_comp_units; + llvm::DenseMap m_comp_units; + llvm::DenseMap m_types; std::unique_ptr m_session_up; uint32_t m_cached_compile_unit_count; + std::unique_ptr m_tu_decl_ctx_up; }; #endif // lldb_Plugins_SymbolFile_PDB_SymbolFilePDB_h_ Index: source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp =================================================================== --- source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp +++ source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp @@ -11,10 +11,12 @@ #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" +#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/LineTable.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolContext.h" +#include "lldb/Symbol/TypeMap.h" #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" #include "llvm/DebugInfo/PDB/IPDBLineNumber.h" @@ -27,6 +29,8 @@ #include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h" #include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h" +#include "Plugins/SymbolFile/PDB/PDBASTParser.h" + using namespace lldb_private; namespace @@ -116,6 +120,10 @@ { lldb::addr_t obj_load_address = m_obj_file->GetFileOffset(); m_session_up->setLoadAddress(obj_load_address); + + TypeSystem *type_system = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus); + ClangASTContext *clang_type_system = llvm::dyn_cast_or_null(type_system); + m_tu_decl_ctx_up = llvm::make_unique(type_system, clang_type_system->GetTranslationUnitDecl()); } uint32_t @@ -245,7 +253,25 @@ lldb_private::Type * SymbolFilePDB::ResolveTypeUID(lldb::user_id_t type_uid) { - return nullptr; + auto find_result = m_types.find(type_uid); + if (find_result != m_types.end()) + return find_result->second.get(); + + TypeSystem *type_system = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus); + ClangASTContext *clang_type_system = llvm::dyn_cast_or_null(type_system); + if (!clang_type_system) + return nullptr; + PDBASTParser *pdb = llvm::dyn_cast(clang_type_system->GetPDBParser()); + if (!pdb) + return nullptr; + + auto pdb_type = m_session_up->getSymbolById(type_uid); + if (pdb_type == nullptr) + return nullptr; + + lldb::TypeSP result = pdb->CreateLLDBTypeFromPDBType(*pdb_type); + m_types.insert(std::make_pair(type_uid, result)); + return result.get(); } bool @@ -264,13 +290,15 @@ lldb_private::CompilerDeclContext SymbolFilePDB::GetDeclContextForUID(lldb::user_id_t uid) { - return lldb_private::CompilerDeclContext(); + // PDB always uses the translation unit decl context for everything. We can improve this later + // but it's not easy because PDB doesn't provide a high enough level of type fidelity in this area. + return *m_tu_decl_ctx_up; } lldb_private::CompilerDeclContext SymbolFilePDB::GetDeclContextContainingUID(lldb::user_id_t uid) { - return lldb_private::CompilerDeclContext(); + return *m_tu_decl_ctx_up; } void @@ -380,10 +408,47 @@ } size_t -SymbolFilePDB::FindTypes(const std::vector &context, bool append, +SymbolFilePDB::FindTypes(const std::vector &contexts, bool append, lldb_private::TypeMap &types) { - return size_t(); + if (!append) + types.Clear(); + + auto global = m_session_up->getGlobalScope(); + for (auto context : contexts) + { + llvm::PDB_SymType sym_type; + switch (context.type) + { + case CompilerContextKind::Structure: + case CompilerContextKind::Class: + case CompilerContextKind::Union: + sym_type = llvm::PDB_SymType::UDT; + break; + case CompilerContextKind::Enumeration: + sym_type = llvm::PDB_SymType::Enum; + break; + case CompilerContextKind::Typedef: + sym_type = llvm::PDB_SymType::Typedef; + break; + default: + // Ignore other types of type contexts, as PDB doesn't contain enough + // information to support them. + continue; + } + auto results = global->findChildren(sym_type, context.name.GetCString(), llvm::PDB_NameSearchFlags::NS_Default); + while (auto result = results->getNext()) + { + // This should cause the type to get cached and stored in the `m_types` lookup. + ResolveTypeUID(result->getSymIndexId()); + + auto iter = m_types.find(result->getSymIndexId()); + if (iter == m_types.end()) + continue; + types.Insert(iter->second); + } + } + return types.GetSize(); } lldb_private::TypeList * @@ -470,7 +535,7 @@ // ParseCompileUnitSupportFiles. But the underlying SDK gives us a globally unique // idenfitifier in the namespace of the PDB. So, we have to do a mapping so that we // can hand out indices. - std::unordered_map index_map; + llvm::DenseMap index_map; BuildSupportFileIdToSupportFileIndexMap(*cu, index_map); auto line_table = llvm::make_unique(sc.comp_unit); @@ -555,7 +620,7 @@ void SymbolFilePDB::BuildSupportFileIdToSupportFileIndexMap(const llvm::PDBSymbolCompiland &cu, - std::unordered_map &index_map) const + llvm::DenseMap &index_map) const { // This is a hack, but we need to convert the source id into an index into the support // files array. We don't want to do path comparisons to avoid basename / full path Index: source/Symbol/ClangASTContext.cpp =================================================================== --- source/Symbol/ClangASTContext.cpp +++ source/Symbol/ClangASTContext.cpp @@ -90,6 +90,7 @@ #include "lldb/Target/Target.h" #include "Plugins/SymbolFile/DWARF/DWARFASTParserClang.h" +#include "Plugins/SymbolFile/PDB/PDBASTParser.h" #include @@ -9435,6 +9436,13 @@ return m_dwarf_ast_parser_ap.get(); } +PDBASTParser * +ClangASTContext::GetPDBParser() +{ + if (!m_pdb_ast_parser_ap) + m_pdb_ast_parser_ap.reset(new PDBASTParser(*this)); + return m_pdb_ast_parser_ap.get(); +} bool ClangASTContext::LayoutRecordType(void *baton,