forked from OSchip/llvm-project
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
This commit is contained in:
parent
5ffa13c473
commit
42dff79068
|
@ -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;
|
||||
|
|
|
@ -2,5 +2,6 @@ set(LLVM_PRIVATE_LINK_COMPONENTS
|
|||
DebugInfoPDB)
|
||||
|
||||
add_lldb_library(lldbPluginSymbolFilePDB
|
||||
PDBASTParser.cpp
|
||||
SymbolFilePDB.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);
|
||||
}
|
|
@ -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_
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
std::unordered_map<uint32_t, lldb::CompUnitSP> m_comp_units;
|
||||
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);
|
||||
|
||||
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_
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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}")
|
||||
|
|
|
@ -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);
|
||||
}
|
Binary file not shown.
|
@ -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
|
||||
{
|
||||
SymbolFilePDB::Terminate();
|
||||
ClangASTContext::Initialize();
|
||||
SymbolFileDWARF::Terminate();
|
||||
ObjectFilePECOFF::Terminate();
|
||||
HostInfo::Terminate();
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
::CoUninitialize();
|
||||
#endif
|
||||
SymbolFilePDB::Terminate();
|
||||
SymbolFileDWARF::Terminate();
|
||||
ObjectFilePECOFF::Terminate();
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue