diff options
| author | Zachary Turner <zturner@google.com> | 2016-04-15 00:21:26 +0000 |
|---|---|---|
| committer | Zachary Turner <zturner@google.com> | 2016-04-15 00:21:26 +0000 |
| commit | 42dff790683ab788286ab94a52bdfe784dd1685b (patch) | |
| tree | ad4806405da541292abcc640ec4ee69f7edfaf1c | |
| parent | 5ffa13c47395c0e9138526108b12711d27c2dbfe (diff) | |
| download | bcm5719-llvm-42dff790683ab788286ab94a52bdfe784dd1685b.tar.gz bcm5719-llvm-42dff790683ab788286ab94a52bdfe784dd1685b.zip | |
Initial support for reading type information from PDBs.
This implements a PDBASTParser and corresponding logic in
SymbolFilePDB to do type lookup by name. This is just a first
pass and leaves many aspects of type lookup unimplemented, and
just focuses on laying the framework. With this patch, you should
be able to lookup basic types by name from a PDB.
Full class definitions are not completed yet, we will instead
just return a forward declaration of the class.
Differential Revision: http://reviews.llvm.org/D18848
Reviewed by: Greg Clayton
llvm-svn: 266392
| -rw-r--r-- | lldb/include/lldb/Symbol/ClangASTContext.h | 12 | ||||
| -rw-r--r-- | lldb/source/Plugins/SymbolFile/PDB/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp | 236 | ||||
| -rw-r--r-- | lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.h | 55 | ||||
| -rw-r--r-- | lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp | 170 | ||||
| -rw-r--r-- | lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h | 22 | ||||
| -rw-r--r-- | lldb/source/Symbol/ClangASTContext.cpp | 32 | ||||
| -rw-r--r-- | lldb/unittests/SymbolFile/PDB/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | lldb/unittests/SymbolFile/PDB/Inputs/test-pdb-types.cpp | 86 | ||||
| -rw-r--r-- | lldb/unittests/SymbolFile/PDB/Inputs/test-pdb-types.pdb | bin | 0 -> 143360 bytes | |||
| -rw-r--r-- | lldb/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp | 246 |
11 files changed, 844 insertions, 20 deletions
diff --git a/lldb/include/lldb/Symbol/ClangASTContext.h b/lldb/include/lldb/Symbol/ClangASTContext.h index 922ce695b58..edfa3d1c2a7 100644 --- a/lldb/include/lldb/Symbol/ClangASTContext.h +++ b/lldb/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 @@ public: //------------------------------------------------------------------ DWARFASTParser * GetDWARFParser() override; + PDBASTParser * + GetPDBParser(); //------------------------------------------------------------------ // ClangASTContext callbacks for external source lookups. @@ -696,7 +699,13 @@ public: bool IsPolymorphicClass (lldb::opaque_compiler_type_t type) override; - + + static bool + IsClassType(lldb::opaque_compiler_type_t type); + + static bool + IsEnumType(lldb::opaque_compiler_type_t type); + bool IsPossibleDynamicType(lldb::opaque_compiler_type_t type, CompilerType *target_type, // Can pass nullptr @@ -1189,6 +1198,7 @@ protected: 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; diff --git a/lldb/source/Plugins/SymbolFile/PDB/CMakeLists.txt b/lldb/source/Plugins/SymbolFile/PDB/CMakeLists.txt index 4e7913b610a..79d8a25d697 100644 --- a/lldb/source/Plugins/SymbolFile/PDB/CMakeLists.txt +++ b/lldb/source/Plugins/SymbolFile/PDB/CMakeLists.txt @@ -2,5 +2,6 @@ set(LLVM_PRIVATE_LINK_COMPONENTS DebugInfoPDB) add_lldb_library(lldbPluginSymbolFilePDB + PDBASTParser.cpp SymbolFilePDB.cpp ) diff --git a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp new file mode 100644 index 00000000000..d4e92bf4f32 --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp @@ -0,0 +1,236 @@ +//===-- 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/ClangUtil.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/PDBSymbolData.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; + } +} +} + +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); + + m_ast.SetHasExternalStorage(clang_type.GetOpaqueQualType(), true); + + 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::eResolveStateForward); + } + 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); + auto enum_values = enum_type->findAllChildren<PDBSymbolData>(); + while (auto enum_value = enum_values->getNext()) + { + if (enum_value->getDataKind() != PDB_DataKind::Constant) + continue; + AddEnumValue(ast_enum, *enum_value); + } + + 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; +} + +bool +PDBASTParser::AddEnumValue(CompilerType enum_type, const llvm::PDBSymbolData &enum_value) const +{ + Declaration decl; + Variant v = enum_value.getValue(); + std::string name = enum_value.getName(); + int64_t raw_value; + switch (v.Type) + { + case PDB_VariantType::Int8: + raw_value = v.Value.Int8; + break; + case PDB_VariantType::Int16: + raw_value = v.Value.Int16; + break; + case PDB_VariantType::Int32: + raw_value = v.Value.Int32; + break; + case PDB_VariantType::Int64: + raw_value = v.Value.Int64; + break; + case PDB_VariantType::UInt8: + raw_value = v.Value.UInt8; + break; + case PDB_VariantType::UInt16: + raw_value = v.Value.UInt16; + break; + case PDB_VariantType::UInt32: + raw_value = v.Value.UInt32; + break; + case PDB_VariantType::UInt64: + raw_value = v.Value.UInt64; + break; + default: + return false; + } + CompilerType underlying_type = m_ast.GetEnumerationIntegerType(enum_type.GetOpaqueQualType()); + uint32_t byte_size = m_ast.getASTContext()->getTypeSize(ClangUtil::GetQualType(underlying_type)); + return m_ast.AddEnumerationValueToEnumerationType(enum_type.GetOpaqueQualType(), underlying_type, decl, + name.c_str(), raw_value, byte_size * 8); +} diff --git a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.h b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.h new file mode 100644 index 00000000000..b82620148ca --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.h @@ -0,0 +1,55 @@ +//===-- 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; +class CompilerType; +} + +namespace llvm +{ +class PDBSymbol; +class PDBSymbolData; +class PDBSymbolTypeBuiltin; +} + +class PDBASTParser +{ +public: + PDBASTParser(lldb_private::ClangASTContext &ast); + ~PDBASTParser(); + + lldb::TypeSP + CreateLLDBTypeFromPDBType(const llvm::PDBSymbol &type); + +private: + bool + AddEnumValue(lldb_private::CompilerType enum_type, const llvm::PDBSymbolData &data) const; + + lldb_private::ClangASTContext &m_ast; + lldb_private::ClangASTImporter m_ast_importer; +}; + +#endif // SymbolFileDWARF_DWARFASTParserClang_h_ diff --git a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp index a6357408551..9a82f4d40fd 100644 --- a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp +++ b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp @@ -9,12 +9,16 @@ #include "SymbolFilePDB.h" +#include "clang/Lex/Lexer.h" + #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" @@ -26,6 +30,13 @@ #include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" #include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h" #include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" + +#include "Plugins/SymbolFile/PDB/PDBASTParser.h" + +#include <regex> using namespace lldb_private; @@ -116,6 +127,10 @@ SymbolFilePDB::InitializeObject() { 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 +260,25 @@ SymbolFilePDB::ParseVariablesForContext(const lldb_private::SymbolContext &sc) 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 +297,15 @@ SymbolFilePDB::GetDeclForUID(lldb::user_id_t uid) 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 @@ -376,14 +411,121 @@ SymbolFilePDB::FindTypes(const lldb_private::SymbolContext &sc, const lldb_priva llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, lldb_private::TypeMap &types) { - return uint32_t(); + if (!append) + types.Clear(); + if (!name) + return 0; + + searched_symbol_files.clear(); + searched_symbol_files.insert(this); + + std::string name_str = name.AsCString(); + + // If this might be a regex, we have to return EVERY symbol and process them one by one, which is going + // to destroy performance on large PDB files. So try really hard not to use a regex match. + if (name_str.find_first_of("[]?*.-+\\") != std::string::npos) + FindTypesByRegex(name_str, max_matches, types); + else + FindTypesByName(name_str, max_matches, types); + return types.GetSize(); +} + +void +SymbolFilePDB::FindTypesByRegex(const std::string ®ex, uint32_t max_matches, lldb_private::TypeMap &types) +{ + // When searching by regex, we need to go out of our way to limit the search space as much as possible, since + // the way this is implemented is by searching EVERYTHING in the PDB and manually doing a regex compare. PDB + // library isn't optimized for regex searches or searches across multiple symbol types at the same time, so the + // best we can do is to search enums, then typedefs, then classes one by one, and do a regex compare against all + // of them. + llvm::PDB_SymType tags_to_search[] = {llvm::PDB_SymType::Enum, llvm::PDB_SymType::Typedef, llvm::PDB_SymType::UDT}; + auto global = m_session_up->getGlobalScope(); + std::unique_ptr<llvm::IPDBEnumSymbols> results; + + std::regex re(regex); + + uint32_t matches = 0; + + for (auto tag : tags_to_search) + { + results = global->findAllChildren(tag); + while (auto result = results->getNext()) + { + if (max_matches > 0 && matches >= max_matches) + break; + + std::string type_name; + if (auto enum_type = llvm::dyn_cast<llvm::PDBSymbolTypeEnum>(result.get())) + type_name = enum_type->getName(); + else if (auto typedef_type = llvm::dyn_cast<llvm::PDBSymbolTypeTypedef>(result.get())) + type_name = typedef_type->getName(); + else if (auto class_type = llvm::dyn_cast<llvm::PDBSymbolTypeUDT>(result.get())) + type_name = class_type->getName(); + else + { + // We're only looking for types that have names. Skip symbols, as well as + // unnamed types such as arrays, pointers, etc. + continue; + } + + if (!std::regex_match(type_name, re)) + continue; + + // This should cause the type to get cached and stored in the `m_types` lookup. + if (!ResolveTypeUID(result->getSymIndexId())) + continue; + + auto iter = m_types.find(result->getSymIndexId()); + if (iter == m_types.end()) + continue; + types.Insert(iter->second); + ++matches; + } + } +} + +void +SymbolFilePDB::FindTypesByName(const std::string &name, uint32_t max_matches, lldb_private::TypeMap &types) +{ + auto global = m_session_up->getGlobalScope(); + std::unique_ptr<llvm::IPDBEnumSymbols> results; + results = global->findChildren(llvm::PDB_SymType::None, name.c_str(), llvm::PDB_NameSearchFlags::NS_Default); + + uint32_t matches = 0; + + while (auto result = results->getNext()) + { + if (max_matches > 0 && matches >= max_matches) + break; + switch (result->getSymTag()) + { + case llvm::PDB_SymType::Enum: + case llvm::PDB_SymType::UDT: + case llvm::PDB_SymType::Typedef: + break; + default: + // We're only looking for types that have names. Skip symbols, as well as + // unnamed types such as arrays, pointers, etc. + continue; + } + + // This should cause the type to get cached and stored in the `m_types` lookup. + if (!ResolveTypeUID(result->getSymIndexId())) + continue; + + auto iter = m_types.find(result->getSymIndexId()); + if (iter == m_types.end()) + continue; + types.Insert(iter->second); + ++matches; + } } 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(); + return 0; } lldb_private::TypeList * @@ -428,6 +570,18 @@ SymbolFilePDB::GetPluginVersion() return 1; } +llvm::IPDBSession & +SymbolFilePDB::GetPDBSession() +{ + return *m_session_up; +} + +const llvm::IPDBSession & +SymbolFilePDB::GetPDBSession() const +{ + return *m_session_up; +} + lldb::CompUnitSP SymbolFilePDB::ParseCompileUnitForSymIndex(uint32_t id) { @@ -470,7 +624,7 @@ SymbolFilePDB::ParseCompileUnitLineTable(const lldb_private::SymbolContext &sc, // 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 +709,7 @@ SymbolFilePDB::ParseCompileUnitLineTable(const lldb_private::SymbolContext &sc, 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 diff --git a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h index 019b4767955..112b54c5901 100644 --- a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h +++ b/lldb/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" @@ -170,6 +169,12 @@ public: uint32_t GetPluginVersion() override; + llvm::IPDBSession & + GetPDBSession(); + + const llvm::IPDBSession & + GetPDBSession() const; + private: lldb::CompUnitSP ParseCompileUnitForSymIndex(uint32_t id); @@ -179,12 +184,21 @@ private: 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; + + void + FindTypesByRegex(const std::string ®ex, uint32_t max_matches, lldb_private::TypeMap &types); + + void + FindTypesByName(const std::string &name, uint32_t max_matches, lldb_private::TypeMap &types); - 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::vector<lldb::TypeSP> m_builtin_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_ diff --git a/lldb/source/Symbol/ClangASTContext.cpp b/lldb/source/Symbol/ClangASTContext.cpp index 7a62f82532b..aab4593a313 100644 --- a/lldb/source/Symbol/ClangASTContext.cpp +++ b/lldb/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> @@ -3442,7 +3443,27 @@ ClangASTContext::IsObjCObjectOrInterfaceType (const CompilerType& type) } bool -ClangASTContext::IsPolymorphicClass (lldb::opaque_compiler_type_t type) +ClangASTContext::IsClassType(lldb::opaque_compiler_type_t type) +{ + if (!type) + return false; + clang::QualType qual_type(GetCanonicalQualType(type)); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + return (type_class == clang::Type::Record); +} + +bool +ClangASTContext::IsEnumType(lldb::opaque_compiler_type_t type) +{ + if (!type) + return false; + clang::QualType qual_type(GetCanonicalQualType(type)); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + return (type_class == clang::Type::Enum); +} + +bool +ClangASTContext::IsPolymorphicClass(lldb::opaque_compiler_type_t type) { if (type) { @@ -5204,7 +5225,7 @@ ClangASTContext::GetNumChildren (lldb::opaque_compiler_type_t type, bool omit_em CompilerType ClangASTContext::GetBuiltinTypeByName (const ConstString &name) { - return GetBasicType (GetBasicTypeEnumeration (name)); + return GetBasicType(GetBasicTypeEnumeration(name)); } lldb::BasicType @@ -9472,6 +9493,13 @@ ClangASTContext::GetDWARFParser() 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, diff --git a/lldb/unittests/SymbolFile/PDB/CMakeLists.txt b/lldb/unittests/SymbolFile/PDB/CMakeLists.txt index 4cb49435b39..fcfb5e3062c 100644 --- a/lldb/unittests/SymbolFile/PDB/CMakeLists.txt +++ b/lldb/unittests/SymbolFile/PDB/CMakeLists.txt @@ -5,6 +5,8 @@ add_lldb_unittest(SymbolFilePDBTests set(test_inputs test-pdb.exe test-pdb.pdb - test-dwarf.exe) + test-dwarf.exe + test-pdb-types.exe + test-pdb-types.pdb) add_unittest_inputs(SymbolFilePDBTests "${test_inputs}") diff --git a/lldb/unittests/SymbolFile/PDB/Inputs/test-pdb-types.cpp b/lldb/unittests/SymbolFile/PDB/Inputs/test-pdb-types.cpp new file mode 100644 index 00000000000..9639a3f4b72 --- /dev/null +++ b/lldb/unittests/SymbolFile/PDB/Inputs/test-pdb-types.cpp @@ -0,0 +1,86 @@ +// Compile with "cl /c /Zi /GR- /EHsc test-pdb-types.cpp"
+// Link with "link test-pdb-types.obj /debug /nodefaultlib /entry:main /out:test-pdb-types.exe"
+
+using namespace std;
+
+// Sizes of builtin types
+static const int sizeof_char = sizeof(char);
+static const int sizeof_uchar = sizeof(unsigned char);
+static const int sizeof_short = sizeof(short);
+static const int sizeof_ushort = sizeof(unsigned short);
+static const int sizeof_int = sizeof(int);
+static const int sizeof_uint = sizeof(unsigned int);
+static const int sizeof_long = sizeof(long);
+static const int sizeof_ulong = sizeof(unsigned long);
+static const int sizeof_longlong = sizeof(long long);
+static const int sizeof_ulonglong = sizeof(unsigned long long);
+static const int sizeof_int64 = sizeof(__int64);
+static const int sizeof_uint64 = sizeof(unsigned __int64);
+static const int sizeof_float = sizeof(float);
+static const int sizeof_double = sizeof(double);
+static const int sizeof_bool = sizeof(bool);
+static const int sizeof_wchar = sizeof(wchar_t);
+
+enum Enum
+{
+ EValue1 = 1,
+ EValue2 = 2,
+};
+
+enum ShortEnum : short
+{
+ ESValue1 = 1,
+ ESValue2 = 2
+};
+
+namespace NS
+{
+class NSClass
+{
+ float f;
+ double d;
+};
+}
+
+class Class
+{
+public:
+ class NestedClass
+ {
+ Enum e;
+ };
+ ShortEnum se;
+};
+
+int
+test_func(int a, int b)
+{
+ return a + b;
+}
+
+typedef Class ClassTypedef;
+typedef NS::NSClass NSClassTypedef;
+int GlobalArray[10];
+
+static const int sizeof_NSClass = sizeof(NS::NSClass);
+static const int sizeof_Class = sizeof(Class);
+static const int sizeof_NestedClass = sizeof(Class::NestedClass);
+static const int sizeof_Enum = sizeof(Enum);
+static const int sizeof_ShortEnum = sizeof(ShortEnum);
+static const int sizeof_ClassTypedef = sizeof(ClassTypedef);
+static const int sizeof_NSClassTypedef = sizeof(NSClassTypedef);
+static const int sizeof_GlobalArray = sizeof(GlobalArray);
+
+int
+main(int argc, char **argv)
+{
+ ShortEnum e1;
+ Enum e2;
+ Class c1;
+ Class::NestedClass c2;
+ NS::NSClass c3;
+
+ ClassTypedef t1;
+ NSClassTypedef t2;
+ return test_func(1, 2);
+}
diff --git a/lldb/unittests/SymbolFile/PDB/Inputs/test-pdb-types.pdb b/lldb/unittests/SymbolFile/PDB/Inputs/test-pdb-types.pdb Binary files differnew file mode 100644 index 00000000000..acf241bcb5d --- /dev/null +++ b/lldb/unittests/SymbolFile/PDB/Inputs/test-pdb-types.pdb diff --git a/lldb/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp b/lldb/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp index b1914997be7..0b96723b6cf 100644 --- a/lldb/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp +++ b/lldb/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp @@ -11,6 +11,8 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/Config/config.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" @@ -20,6 +22,7 @@ #include "lldb/Core/ModuleSpec.h" #include "lldb/Host/FileSpec.h" #include "lldb/Host/HostInfo.h" +#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/LineTable.h" #include "lldb/Symbol/SymbolVendor.h" @@ -29,9 +32,12 @@ #include "Plugins/SymbolFile/PDB/SymbolFilePDB.h" #if defined(_MSC_VER) +#include "lldb/Host/windows/windows.h" #include <objbase.h> #endif +#include <algorithm> + extern const char *TestMainArgv0; using namespace lldb_private; @@ -42,13 +48,17 @@ public: void SetUp() override { +// Initialize and TearDown the plugin every time, so we get a brand new +// AST every time so that modifications to the AST from each test don't +// leak into the next test. #if defined(_MSC_VER) ::CoInitializeEx(nullptr, COINIT_MULTITHREADED); #endif - HostInfoBase::Initialize(); + HostInfo::Initialize(); ObjectFilePECOFF::Initialize(); SymbolFileDWARF::Initialize(); + ClangASTContext::Initialize(); SymbolFilePDB::Initialize(); llvm::StringRef exe_folder = llvm::sys::path::parent_path(TestMainArgv0); @@ -57,24 +67,30 @@ public: m_pdb_test_exe = inputs_folder; m_dwarf_test_exe = inputs_folder; + m_types_test_exe = inputs_folder; llvm::sys::path::append(m_pdb_test_exe, "test-pdb.exe"); llvm::sys::path::append(m_dwarf_test_exe, "test-dwarf.exe"); + llvm::sys::path::append(m_types_test_exe, "test-pdb-types.exe"); } void TearDown() override { -#if defined(_MSC_VER) - ::CoUninitialize(); -#endif SymbolFilePDB::Terminate(); + ClangASTContext::Initialize(); SymbolFileDWARF::Terminate(); ObjectFilePECOFF::Terminate(); + HostInfo::Terminate(); + +#if defined(_MSC_VER) + ::CoUninitialize(); +#endif } protected: llvm::SmallString<128> m_pdb_test_exe; llvm::SmallString<128> m_dwarf_test_exe; + llvm::SmallString<128> m_types_test_exe; bool FileSpecMatchesAsBaseOrFull(const FileSpec &left, const FileSpec &right) const @@ -116,6 +132,35 @@ protected: } return false; } + + int + GetGlobalConstantInteger(const llvm::IPDBSession &session, llvm::StringRef var) const + { + auto global = session.getGlobalScope(); + auto results = global->findChildren(llvm::PDB_SymType::Data, var, llvm::PDB_NameSearchFlags::NS_Default); + uint32_t count = results->getChildCount(); + if (count == 0) + return -1; + + auto item = results->getChildAtIndex(0); + auto symbol = llvm::dyn_cast<llvm::PDBSymbolData>(item.get()); + if (!symbol) + return -1; + llvm::Variant value = symbol->getValue(); + switch (value.Type) + { + case llvm::PDB_VariantType::Int16: + return value.Value.Int16; + case llvm::PDB_VariantType::Int32: + return value.Value.Int32; + case llvm::PDB_VariantType::UInt16: + return value.Value.UInt16; + case llvm::PDB_VariantType::UInt32: + return value.Value.UInt32; + default: + return 0; + } + } }; #if defined(HAVE_DIA_SDK) @@ -342,3 +387,196 @@ TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestLineTablesMatchSpecific)) VerifyLineEntry(module, sc, source_file, *lt, 9, 0x401045); VerifyLineEntry(module, sc, header1, *lt, 9, 0x401090); } + +TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestSimpleClassTypes)) +{ + FileSpec fspec(m_types_test_exe.c_str(), false); + ArchSpec aspec("i686-pc-windows"); + lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec); + + SymbolVendor *plugin = module->GetSymbolVendor(); + SymbolFilePDB *symfile = static_cast<SymbolFilePDB *>(plugin->GetSymbolFile()); + const llvm::IPDBSession &session = symfile->GetPDBSession(); + SymbolContext sc; + llvm::DenseSet<SymbolFile *> searched_files; + TypeMap results; + EXPECT_EQ(1, symfile->FindTypes(sc, ConstString("Class"), nullptr, false, 0, searched_files, results)); + EXPECT_EQ(1, results.GetSize()); + lldb::TypeSP udt_type = results.GetTypeAtIndex(0); + EXPECT_EQ(ConstString("Class"), udt_type->GetName()); + CompilerType compiler_type = udt_type->GetForwardCompilerType(); + EXPECT_TRUE(ClangASTContext::IsClassType(compiler_type.GetOpaqueQualType())); + EXPECT_EQ(GetGlobalConstantInteger(session, "sizeof_Class"), udt_type->GetByteSize()); +} + +TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestNestedClassTypes)) +{ + FileSpec fspec(m_types_test_exe.c_str(), false); + ArchSpec aspec("i686-pc-windows"); + lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec); + + SymbolVendor *plugin = module->GetSymbolVendor(); + SymbolFilePDB *symfile = static_cast<SymbolFilePDB *>(plugin->GetSymbolFile()); + const llvm::IPDBSession &session = symfile->GetPDBSession(); + SymbolContext sc; + llvm::DenseSet<SymbolFile *> searched_files; + TypeMap results; + EXPECT_EQ(1, symfile->FindTypes(sc, ConstString("Class::NestedClass"), nullptr, false, 0, searched_files, results)); + EXPECT_EQ(1, results.GetSize()); + lldb::TypeSP udt_type = results.GetTypeAtIndex(0); + EXPECT_EQ(ConstString("Class::NestedClass"), udt_type->GetName()); + CompilerType compiler_type = udt_type->GetForwardCompilerType(); + EXPECT_TRUE(ClangASTContext::IsClassType(compiler_type.GetOpaqueQualType())); + EXPECT_EQ(GetGlobalConstantInteger(session, "sizeof_NestedClass"), udt_type->GetByteSize()); +} + +TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestClassInNamespace)) +{ + FileSpec fspec(m_types_test_exe.c_str(), false); + ArchSpec aspec("i686-pc-windows"); + lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec); + + SymbolVendor *plugin = module->GetSymbolVendor(); + SymbolFilePDB *symfile = static_cast<SymbolFilePDB *>(plugin->GetSymbolFile()); + const llvm::IPDBSession &session = symfile->GetPDBSession(); + SymbolContext sc; + llvm::DenseSet<SymbolFile *> searched_files; + TypeMap results; + EXPECT_EQ(1, symfile->FindTypes(sc, ConstString("NS::NSClass"), nullptr, false, 0, searched_files, results)); + EXPECT_EQ(1, results.GetSize()); + lldb::TypeSP udt_type = results.GetTypeAtIndex(0); + EXPECT_EQ(ConstString("NS::NSClass"), udt_type->GetName()); + CompilerType compiler_type = udt_type->GetForwardCompilerType(); + EXPECT_TRUE(ClangASTContext::IsClassType(compiler_type.GetOpaqueQualType())); + EXPECT_EQ(GetGlobalConstantInteger(session, "sizeof_NSClass"), udt_type->GetByteSize()); +} + +TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestEnumTypes)) +{ + FileSpec fspec(m_types_test_exe.c_str(), false); + ArchSpec aspec("i686-pc-windows"); + lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec); + + SymbolVendor *plugin = module->GetSymbolVendor(); + SymbolFilePDB *symfile = static_cast<SymbolFilePDB *>(plugin->GetSymbolFile()); + const llvm::IPDBSession &session = symfile->GetPDBSession(); + SymbolContext sc; + llvm::DenseSet<SymbolFile *> searched_files; + const char *EnumsToCheck[] = {"Enum", "ShortEnum"}; + for (auto Enum : EnumsToCheck) + { + TypeMap results; + EXPECT_EQ(1, symfile->FindTypes(sc, ConstString(Enum), nullptr, false, 0, searched_files, results)); + EXPECT_EQ(1, results.GetSize()); + lldb::TypeSP enum_type = results.GetTypeAtIndex(0); + EXPECT_EQ(ConstString(Enum), enum_type->GetName()); + CompilerType compiler_type = enum_type->GetFullCompilerType(); + EXPECT_TRUE(ClangASTContext::IsEnumType(compiler_type.GetOpaqueQualType())); + clang::EnumDecl *enum_decl = ClangASTContext::GetAsEnumDecl(compiler_type); + EXPECT_NE(nullptr, enum_decl); + EXPECT_EQ(2, std::distance(enum_decl->enumerator_begin(), enum_decl->enumerator_end())); + + std::string sizeof_var = "sizeof_"; + sizeof_var.append(Enum); + EXPECT_EQ(GetGlobalConstantInteger(session, sizeof_var.c_str()), enum_type->GetByteSize()); + } +} + +TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestArrayTypes)) +{ + // In order to get this test working, we need to support lookup by symbol name. Because array + // types themselves do not have names, only the symbols have names (i.e. the name of the array). +} + +TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestFunctionTypes)) +{ + // In order to get this test working, we need to support lookup by symbol name. Because array + // types themselves do not have names, only the symbols have names (i.e. the name of the array). +} + +TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestTypedefs)) +{ + FileSpec fspec(m_types_test_exe.c_str(), false); + ArchSpec aspec("i686-pc-windows"); + lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec); + + SymbolVendor *plugin = module->GetSymbolVendor(); + SymbolFilePDB *symfile = static_cast<SymbolFilePDB *>(plugin->GetSymbolFile()); + const llvm::IPDBSession &session = symfile->GetPDBSession(); + SymbolContext sc; + llvm::DenseSet<SymbolFile *> searched_files; + TypeMap results; + + const char *TypedefsToCheck[] = {"ClassTypedef", "NSClassTypedef"}; + for (auto Typedef : TypedefsToCheck) + { + TypeMap results; + EXPECT_EQ(1, symfile->FindTypes(sc, ConstString(Typedef), nullptr, false, 0, searched_files, results)); + EXPECT_EQ(1, results.GetSize()); + lldb::TypeSP typedef_type = results.GetTypeAtIndex(0); + EXPECT_EQ(ConstString(Typedef), typedef_type->GetName()); + CompilerType compiler_type = typedef_type->GetFullCompilerType(); + ClangASTContext *clang_type_system = llvm::dyn_cast_or_null<ClangASTContext>(compiler_type.GetTypeSystem()); + EXPECT_TRUE(clang_type_system->IsTypedefType(compiler_type.GetOpaqueQualType())); + + std::string sizeof_var = "sizeof_"; + sizeof_var.append(Typedef); + EXPECT_EQ(GetGlobalConstantInteger(session, sizeof_var.c_str()), typedef_type->GetByteSize()); + } +} + +TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestRegexNameMatch)) +{ + FileSpec fspec(m_types_test_exe.c_str(), false); + ArchSpec aspec("i686-pc-windows"); + lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec); + + SymbolVendor *plugin = module->GetSymbolVendor(); + SymbolFilePDB *symfile = static_cast<SymbolFilePDB *>(plugin->GetSymbolFile()); + SymbolContext sc; + llvm::DenseSet<SymbolFile *> searched_files; + TypeMap results; + int num_results = symfile->FindTypes(sc, ConstString(".*"), nullptr, false, 0, searched_files, results); + EXPECT_GT(num_results, 1); + EXPECT_EQ(num_results, results.GetSize()); +} + +TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestMaxMatches)) +{ + FileSpec fspec(m_types_test_exe.c_str(), false); + ArchSpec aspec("i686-pc-windows"); + lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec); + + SymbolVendor *plugin = module->GetSymbolVendor(); + SymbolFilePDB *symfile = static_cast<SymbolFilePDB *>(plugin->GetSymbolFile()); + SymbolContext sc; + llvm::DenseSet<SymbolFile *> searched_files; + TypeMap results; + int num_results = symfile->FindTypes(sc, ConstString(".*"), nullptr, false, 0, searched_files, results); + // Try to limit ourselves from 1 to 10 results, otherwise we could be doing this thousands of times. + // The idea is just to make sure that for a variety of values, the number of limited results always + // comes out to the number we are expecting. + int iterations = std::min(num_results, 10); + for (int i = 1; i <= iterations; ++i) + { + int num_limited_results = symfile->FindTypes(sc, ConstString(".*"), nullptr, false, i, searched_files, results); + EXPECT_EQ(i, num_limited_results); + EXPECT_EQ(num_limited_results, results.GetSize()); + } +} + +TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestNullName)) +{ + FileSpec fspec(m_types_test_exe.c_str(), false); + ArchSpec aspec("i686-pc-windows"); + lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec); + + SymbolVendor *plugin = module->GetSymbolVendor(); + SymbolFilePDB *symfile = static_cast<SymbolFilePDB *>(plugin->GetSymbolFile()); + SymbolContext sc; + llvm::DenseSet<SymbolFile *> searched_files; + TypeMap results; + int num_results = symfile->FindTypes(sc, ConstString(), nullptr, false, 0, searched_files, results); + EXPECT_EQ(0, num_results); + EXPECT_EQ(0, results.GetSize()); +} |

