zturner created this revision. zturner added a reviewer: clayborg. zturner added a subscriber: lldb-commits.
This code is still untested aside from that it compiles. I mostly want to put an early work-in-progress up here to make sure I'm on the right path and am not doing anything fundamentally wrong. Not all types are supported, and I don't intend to support all types with this initial commit. Things like const / volatile are not important for a first pass, and I'm only looking at getting the most common basic types of types working. One oddity of PDB is that the debug info does not maintain enough information to accurately reconstruct the DeclContext hierarchy. If you have this: ``` namespace Foo { class Bar { class Baz { }; }; } ``` then that will appear in the PDB as a type with the name `Foo::Bar::Baz`, and there's no information about whether `Foo` and `Bar` are namespaces or classes. It is possible to give a best effort attempt, but it's going to be outside the scope of this patch. So, for now, I intend to put every single type under the master translation unit decl with fully scoped names. This isn't perfect, but we can iterate on it in the future. Again, this is a work in progress, mostly just want to make sure this looks like the right approach. http://reviews.llvm.org/D18848 Files: include/lldb/Symbol/ClangASTContext.h source/Plugins/SymbolFile/PDB/CMakeLists.txt source/Plugins/SymbolFile/PDB/PDBASTParser.cpp source/Plugins/SymbolFile/PDB/PDBASTParser.h source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp source/Plugins/SymbolFile/PDB/SymbolFilePDB.h source/Symbol/ClangASTContext.cpp
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 <stdio.h> @@ -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, 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 <unordered_map> - #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<uint32_t, uint32_t> &index_map) const; + llvm::DenseMap<uint32_t, uint32_t> &index_map) const; - std::unordered_map<uint32_t, lldb::CompUnitSP> m_comp_units; + llvm::DenseMap<uint32_t, lldb::CompUnitSP> m_comp_units; + llvm::DenseMap<uint32_t, lldb::TypeSP> m_types; std::unique_ptr<llvm::IPDBSession> m_session_up; uint32_t m_cached_compile_unit_count; + std::unique_ptr<lldb_private::CompilerDeclContext> 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<ClangASTContext>(type_system); + m_tu_decl_ctx_up = llvm::make_unique<CompilerDeclContext>(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<ClangASTContext>(type_system); + if (!clang_type_system) + return nullptr; + PDBASTParser *pdb = llvm::dyn_cast<PDBASTParser>(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<lldb_private::CompilerContext> &context, bool append, +SymbolFilePDB::FindTypes(const std::vector<lldb_private::CompilerContext> &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<uint32_t, uint32_t> index_map; + llvm::DenseMap<uint32_t, uint32_t> index_map; BuildSupportFileIdToSupportFileIndexMap(*cu, index_map); auto line_table = llvm::make_unique<LineTable>(sc.comp_unit); @@ -555,7 +620,7 @@ void SymbolFilePDB::BuildSupportFileIdToSupportFileIndexMap(const llvm::PDBSymbolCompiland &cu, - std::unordered_map<uint32_t, uint32_t> &index_map) const + llvm::DenseMap<uint32_t, uint32_t> &index_map) const { // This is a hack, but we need to convert the source id into an index into the support // files array. We don't want to do path comparisons to avoid basename / full path 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<const clang::FieldDecl *, uint64_t> &field_offsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &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<PDBSymbolTypeUDT>(&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>(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<PDBSymbolTypeBuiltin>(&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>(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<PDBSymbolTypeEnum>(&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>(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<PDBSymbolTypeTypedef>(&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>(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<PDBSymbolTypeFunctionSig>(&type)) + { + auto arg_enum = func_sig->getArguments(); + uint32_t num_args = arg_enum->getChildCount(); + std::vector<CompilerType> 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<Type>(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<PDBSymbolTypeArray>(&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<Type>(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/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: 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<clang::SelectorTable> m_selector_table_ap; std::unique_ptr<clang::Builtin::Context> m_builtins_ap; std::unique_ptr<DWARFASTParserClang> m_dwarf_ast_parser_ap; + std::unique_ptr<PDBASTParser> m_pdb_ast_parser_ap; std::unique_ptr<ClangASTSource> m_scratch_ast_source_ap; std::unique_ptr<clang::MangleContext> m_mangle_ctx_ap; CompleteTagDeclCallback m_callback_tag_decl;
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits