[PDB] Restore AST from PDB symbols

Summary:
This patch adds an implementation of retrieving of declarations and declaration
contexts based on PDB symbols.

PDB has different type symbols for const-qualified types, and this
implementation ensures that only one declaration was created for both const
and non-const types, but creates different compiler types for them.

The implementation also processes the case when there are two symbols
corresponding to a variable. It's possible e.g. for class static variables,
they has one global symbol and one symbol belonging to a class.

PDB has no info about namespaces, so this implementation parses the full symbol
name and tries to figure out if the symbol belongs to namespace or not,
and then creates nested namespaces if necessary.

Reviewers: asmith, zturner, labath

Reviewed By: asmith

Subscribers: aleksandr.urakov, teemperor, lldb-commits, stella.stamenova

Tags: #lldb

Differential Revision: https://reviews.llvm.org/D51162

llvm-svn: 341782
This commit is contained in:
Aleksandr Urakov 2018-09-10 08:08:43 +00:00
parent 59491a1fa9
commit 709426b33a
12 changed files with 868 additions and 189 deletions

View File

@ -214,19 +214,24 @@ public:
static CompilerType GetTypeForDecl(clang::ObjCInterfaceDecl *objc_decl);
template <typename RecordDeclType>
CompilerType GetTypeForIdentifier(const ConstString &type_name) {
CompilerType
GetTypeForIdentifier(const ConstString &type_name,
clang::DeclContext *decl_context = nullptr) {
CompilerType compiler_type;
if (type_name.GetLength()) {
clang::ASTContext *ast = getASTContext();
if (ast) {
if (!decl_context)
decl_context = ast->getTranslationUnitDecl();
clang::IdentifierInfo &myIdent =
ast->Idents.get(type_name.GetCString());
clang::DeclarationName myName =
ast->DeclarationNames.getIdentifier(&myIdent);
clang::DeclContext::lookup_result result =
ast->getTranslationUnitDecl()->lookup(myName);
decl_context->lookup(myName);
if (!result.empty()) {
clang::NamedDecl *named_decl = result[0];
@ -881,7 +886,7 @@ public:
//----------------------------------------------------------------------
// Modifying Enumeration types
//----------------------------------------------------------------------
bool AddEnumerationValueToEnumerationType(
clang::EnumConstantDecl *AddEnumerationValueToEnumerationType(
lldb::opaque_compiler_type_t type,
const CompilerType &enumerator_qual_type, const Declaration &decl,
const char *name, int64_t enum_value, uint32_t enum_value_bit_size);
@ -937,6 +942,8 @@ public:
static clang::TagDecl *GetAsTagDecl(const CompilerType &type);
static clang::TypedefNameDecl *GetAsTypedefDecl(const CompilerType &type);
clang::CXXRecordDecl *GetAsCXXRecordDecl(lldb::opaque_compiler_type_t type);
static clang::ObjCInterfaceDecl *

View File

@ -0,0 +1,47 @@
namespace N0 {
namespace N1 {
namespace {
enum Enum { Enum_0 = 1, Enum_1 = 2, Enum_2 = 4, Enum_3 = 8 };
}
Enum Global = Enum_3;
struct Base {
Enum m_e = Enum_1;
};
class Class : public Base {
public:
Class(Enum e) : m_ce(e) {}
static int StaticFunc(const Class &c) {
return c.PrivateFunc(c.m_inner) + Global + ClassStatic;
}
const Enum m_ce;
static int ClassStatic;
private:
struct Inner {
char x;
short y;
int z;
};
int PrivateFunc(const Inner &i) const { return i.z; }
Inner m_inner{};
};
int Class::ClassStatic = 7;
void foo() { Class::StaticFunc(Class(Enum_0)); }
} // namespace N1
} // namespace N0
int main() {
N0::N1::foo();
return 0;
}

View File

@ -0,0 +1,77 @@
REQUIRES: windows
RUN: cl /Zi /GS- /c %S/Inputs/AstRestoreTest.cpp /Fo%t.obj
RUN: link /debug:full /nodefaultlib /entry:main %t.obj /out:%t.exe
RUN: lldb-test symbols -dump-ast %t.exe | FileCheck --check-prefix=ENUM %s
RUN: lldb-test symbols -dump-ast %t.exe | FileCheck --check-prefix=GLOBAL %s
RUN: lldb-test symbols -dump-ast %t.exe | FileCheck --check-prefix=BASE %s
RUN: lldb-test symbols -dump-ast %t.exe | FileCheck --check-prefix=CLASS %s
RUN: lldb-test symbols -dump-ast %t.exe | FileCheck --check-prefix=INNER %s
RUN: lldb-test symbols -dump-ast %t.exe | FileCheck --check-prefix=FOO %s
RUN: lldb-test symbols -dump-ast %t.exe | FileCheck --check-prefix=MAIN %s
ENUM: Module: {{.*}}
ENUM: namespace N0 {
ENUM: namespace N1 {
ENUM: namespace {
ENUM: enum Enum {
ENUM: Enum_0,
ENUM: Enum_1,
ENUM: Enum_2,
ENUM: Enum_3
ENUM: };
ENUM: }
ENUM: }
ENUM: }
GLOBAL: Module: {{.*}}
GLOBAL: namespace N0 {
GLOBAL: namespace N1 {
GLOBAL: N0::N1::(anonymous namespace)::Enum Global;
GLOBAL: }
GLOBAL: }
BASE: Module: {{.*}}
BASE: namespace N0 {
BASE: namespace N1 {
BASE: struct Base {
BASE: N0::N1::(anonymous namespace)::Enum m_e;
BASE: };
BASE: }
BASE: }
CLASS: Module: {{.*}}
CLASS: namespace N0 {
CLASS: namespace N1 {
CLASS: class Class : public N0::N1::Base {
CLASS-DAG: const N0::N1::(anonymous namespace)::Enum m_ce;
CLASS-DAG: static int ClassStatic;
CLASS-DAG: N0::N1::Class::Inner m_inner;
CLASS-DAG: {{(inline )?}}Class(N0::N1::(anonymous namespace)::Enum);
CLASS-DAG: static {{(inline )?}}int StaticFunc(const N0::N1::Class &);
CLASS-DAG: {{(inline )?}}int PrivateFunc(const N0::N1::Class::Inner &);
CLASS: };
CLASS: }
CLASS: }
INNER: Module: {{.*}}
INNER: namespace N0 {
INNER: namespace N1 {
INNER: class Class : public N0::N1::Base {
INNER: struct Inner {
INNER: signed char x;
INNER: short y;
INNER: int z;
INNER: };
INNER: };
INNER: }
INNER: }
FOO: Module: {{.*}}
FOO: namespace N0 {
FOO: namespace N1 {
FOO: void foo();
FOO: }
FOO: }
MAIN: Module: {{.*}}
MAIN: int main();

View File

@ -61,30 +61,30 @@ UNNAMED-STRUCT-SAME: struct UnnamedStruct {
UNNAMED-STRUCT: int a;
UNNAMED-STRUCT:}
BASE: name = "MemberTest::Base", size = 4, decl = ClassLayoutTest.cpp:59
BASE-SAME: class MemberTest::Base {
BASE: name = "Base", size = 4, decl = ClassLayoutTest.cpp:59
BASE-SAME: class Base {
BASE: int a;
BASE: void {{.*}}Base();
BASE: {{.*}}~Base();
BASE: int {{.*}}Get();
BASE: Base();
BASE: ~Base();
BASE: int Get();
BASE:}
FRIEND: name = "MemberTest::Friend", size = 1, decl = ClassLayoutTest.cpp:70
FRIEND-SAME: class MemberTest::Friend {
FRIEND: name = "Friend", size = 1, decl = ClassLayoutTest.cpp:70
FRIEND-SAME: class Friend {
FRIEND: int f();
FRIEND: }
CLASS: name = "MemberTest::Class", size = 88, decl = ClassLayoutTest.cpp:74
CLASS-SAME: class MemberTest::Class : public MemberTest::Base {
CLASS: name = "Class", size = 88, decl = ClassLayoutTest.cpp:74
CLASS-SAME: class Class : public MemberTest::Base {
CLASS: static int m_static;
CLASS: int m_public;
CLASS: Struct m_struct;
CLASS: Union m_union;
CLASS: int m_private;
CLASS: int m_protected;
CLASS: void Class();
CLASS: void Class(int);
CLASS: ~MemberTest::Class();
CLASS: Class();
CLASS: Class(int);
CLASS: ~Class();
CLASS: static int {{.*}}StaticMemberFunc(int, ...);
CLASS: int Get();
CLASS: int f(MemberTest::Friend);

View File

@ -14,11 +14,11 @@ CHECK-ONE-DAG: [[TY0:.*]]: Type{[[UID0:.*]]} , name = "Func_arg_array", decl =
CHECK-ONE-DAG: [[TY1:.*]]: Type{[[UID1:.*]]} , name = "Func_arg_void", decl = FuncSymbolsTestMain.cpp:4, compiler_type = {{.*}} void (void)
CHECK-ONE-DAG: [[TY2:.*]]: Type{[[UID2:.*]]} , name = "Func_arg_none", decl = FuncSymbolsTestMain.cpp:5, compiler_type = {{.*}} void (void)
CHECK-ONE-DAG: [[TY3:.*]]: Type{[[UID3:.*]]} , name = "Func_varargs", decl = FuncSymbolsTestMain.cpp:6, compiler_type = {{.*}} void (...)
CHECK-ONE-DAG: [[TY4:.*]]: Type{[[UID4:.*]]} , name = "NS::Func", decl = FuncSymbolsTestMain.cpp:28, compiler_type = {{.*}} void (signed char, int)
CHECK-ONE-DAG: [[TY4:.*]]: Type{[[UID4:.*]]} , name = "Func", decl = FuncSymbolsTestMain.cpp:28, compiler_type = {{.*}} void (signed char, int)
CHECK-ONE-DAG: [[TY5:.*]]: Type{[[UID5:.*]]} , name = "main", decl = FuncSymbolsTestMain.cpp:44, compiler_type = {{.*}} int (void)
CHECK-ONE-DAG: [[TY6:.*]]: Type{[[UID6:.*]]} , name = "`anonymous namespace'::Func", decl = FuncSymbolsTestMain.cpp:24, compiler_type = {{.*}} void (int, const long, volatile _Bool, ...)
CHECK-ONE-DAG: [[TY6:.*]]: Type{[[UID6:.*]]} , name = "Func", decl = FuncSymbolsTestMain.cpp:24, compiler_type = {{.*}} void (int, const long, volatile _Bool, ...)
CHECK-ONE-DAG: [[TY7:.*]]: Type{[[UID7:.*]]} , name = "StaticFunction", decl = FuncSymbolsTestMain.cpp:35, compiler_type = {{.*}} long (int)
CHECK-ONE-DAG: [[TY8:.*]]: Type{[[UID8:.*]]} , name = "MemberTest::A::Func", decl = FuncSymbolsTestMain.cpp:12, compiler_type = {{.*}} int (int, ...)
CHECK-ONE-DAG: [[TY8:.*]]: Type{[[UID8:.*]]} , name = "Func", decl = FuncSymbolsTestMain.cpp:12, compiler_type = {{.*}} int (int, ...)
CHECK-ONE-DAG: [[TY9:.*]]: Type{[[UID9:.*]]} , name = "TemplateFunc<1,int>", decl = FuncSymbolsTestMain.cpp:18, compiler_type = {{.*}} void (int)
CHECK-ONE-DAG: [[TY10:.*]]: Type{[[UID10:.*]]} , name = "TemplateFunc<1,int,int,int>", decl = FuncSymbolsTestMain.cpp:18, compiler_type = {{.*}} void (int, int, int)
CHECK-ONE-DAG: [[TY11:.*]]: Type{[[UID11:.*]]} , name = "InlinedFunction", decl = FuncSymbolsTestMain.cpp:40, compiler_type = {{.*}} void (long)
@ -39,7 +39,7 @@ CHECK-ONE-DAG: Function{[[UID11]]}, mangled = ?InlinedFunction@@YAXJ@Z, demangle
; We expect new types observed in another compile unit
CHECK-TWO-DAG: [[TY30:.*]]: Type{[[UID30:.*]]} , name = "FunctionCall", decl = FuncSymbols.cpp:13, compiler_type = {{.*}} void (void)
CHECK-TWO-DAG: [[TY31:.*]]: Type{[[UID31:.*]]} , name = "`anonymous namespace'::StaticFunction", decl = FuncSymbols.cpp:4, compiler_type = {{.*}} long (int)
CHECK-TWO-DAG: [[TY31:.*]]: Type{[[UID31:.*]]} , name = "StaticFunction", decl = FuncSymbols.cpp:4, compiler_type = {{.*}} long (int)
CHECK-TWO-DAG: [[TY32:.*]]: Type{[[UID32:.*]]} , name = "InlinedFunction", decl = FuncSymbols.cpp:10, compiler_type = {{.*}} int (long)
CHECK-TWO: {{.*}}: CompileUnit{{.*}}, language = "c++", file = '{{.*}}\FuncSymbols.cpp'

View File

@ -10,11 +10,11 @@ RUN: lldb-test symbols %T/PointerTypeTest.cpp.exe | FileCheck --check-prefix=F %
CHECK: Module [[MOD:.*]]
CHECK: {{^[0-9A-F]+}}: CompileUnit{{[{]0x[0-9a-f]+[}]}}, language = "c++", file = '{{.*}}\PointerTypeTest.cpp'
MAIN-ST-F: name = "main::ST::f"
MAIN-ST-F: name = "f"
MAIN-ST-F-SAME: decl = PointerTypeTest.cpp:8
MAIN-ST-F-SAME: compiler_type = {{.*}} int (int)
MAIN-ST: name = "main::ST", size = 4, decl = PointerTypeTest.cpp:6, compiler_type = {{.*}} struct main::ST {
MAIN-ST: name = "ST", size = 4, decl = PointerTypeTest.cpp:6, compiler_type = {{.*}} struct ST {
MAIN-ST-NEXT: int a;
MAIN-ST-NEXT: int {{.*}}f(int);
MAIN-ST-NEXT:}
@ -26,13 +26,13 @@ MAIN-SAME: (int (*)[2][4]), scope = local
MAIN: Variable{{.*}}, name = "p_int"
MAIN-SAME: (int *), scope = local
MAIN: Variable{{.*}}, name = "p_member_field"
MAIN-SAME: (int main::ST::*), scope = local
MAIN-SAME: (int ST::*), scope = local
MAIN: Variable{{.*}}, name = "p_member_method"
MAIN-SAME: (int (main::ST::*)(int)), scope = local
MAIN-SAME: (int (ST::*)(int)), scope = local
F: Function{[[FID2:.*]]}, demangled = {{.*}}f(int)
F-NEXT: Block{[[FID2]]}
F: Variable{{.*}}, name = "this"
F-SAME: (main::ST *), scope = parameter, location = {{.*}}, artificial
F-SAME: (ST *), scope = parameter, location = {{.*}}, artificial
F: Variable{{.*}}, name = "x"
F-SAME: (int), scope = parameter, decl = PointerTypeTest.cpp:8

View File

@ -21,6 +21,7 @@
#include "lldb/Symbol/ClangUtil.h"
#include "lldb/Symbol/Declaration.h"
#include "lldb/Symbol/SymbolFile.h"
#include "lldb/Symbol/TypeMap.h"
#include "lldb/Symbol/TypeSystem.h"
#include "llvm/DebugInfo/PDB/IPDBLineNumber.h"
@ -244,8 +245,8 @@ AccessType GetAccessibilityForUdt(const PDBSymbolTypeUDT &udt) {
return GetDefaultAccessibilityForUdtKind(parent_udt->getUdtKind());
}
clang::MSInheritanceAttr::Spelling GetMSInheritance(
const PDBSymbolTypeUDT &udt) {
clang::MSInheritanceAttr::Spelling
GetMSInheritance(const PDBSymbolTypeUDT &udt) {
int base_count = 0;
bool has_virtual = false;
@ -263,6 +264,46 @@ clang::MSInheritanceAttr::Spelling GetMSInheritance(
return clang::MSInheritanceAttr::Keyword_multiple_inheritance;
return clang::MSInheritanceAttr::Keyword_single_inheritance;
}
std::unique_ptr<llvm::pdb::PDBSymbol>
GetClassOrFunctionParent(const llvm::pdb::PDBSymbol &symbol) {
const IPDBSession &session = symbol.getSession();
const IPDBRawSymbol &raw = symbol.getRawSymbol();
auto class_parent_id = raw.getClassParentId();
if (auto class_parent = session.getSymbolById(class_parent_id))
return class_parent;
auto lexical_parent_id = raw.getLexicalParentId();
auto lexical_parent = session.getSymbolById(lexical_parent_id);
if (!lexical_parent)
return nullptr;
auto lexical_parent_tag = lexical_parent->getSymTag();
if (lexical_parent_tag == PDB_SymType::Function)
return lexical_parent;
if (lexical_parent_tag == PDB_SymType::Exe)
return nullptr;
return GetClassOrFunctionParent(*lexical_parent);
}
clang::NamedDecl *
GetDeclFromContextByName(const clang::ASTContext &ast,
const clang::DeclContext &decl_context,
llvm::StringRef name) {
clang::IdentifierInfo &ident = ast.Idents.get(name);
clang::DeclarationName decl_name = ast.DeclarationNames.getIdentifier(&ident);
clang::DeclContext::lookup_result result = decl_context.lookup(decl_name);
if (result.empty())
return nullptr;
return result[0];
}
bool IsAnonymousNamespaceName(const std::string &name) {
return name == "`anonymous namespace'" | name == "`anonymous-namespace'";
}
} // namespace
PDBASTParser::PDBASTParser(lldb_private::ClangASTContext &ast) : m_ast(ast) {}
@ -272,13 +313,7 @@ PDBASTParser::~PDBASTParser() {}
// DebugInfoASTParser interface
lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const 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;
switch (type.getSymTag()) {
case PDB_SymType::BaseClass: {
auto symbol_file = m_ast.GetSymbolFile();
@ -304,21 +339,66 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) {
return nullptr;
// Ignore unnamed-tag UDTs.
if (udt->getName().empty())
auto name = PDBNameDropScope(udt->getName());
if (name.empty())
return nullptr;
auto access = GetAccessibilityForUdt(*udt);
auto decl_context = GetDeclContextContainingSymbol(type);
auto tag_type_kind = TranslateUdtKind(udt->getUdtKind());
// Check if such an UDT already exists in the current context.
// This may occur with const or volatile types. There are separate type
// symbols in PDB for types with const or volatile modifiers, but we need
// to create only one declaration for them all.
Type::ResolveStateTag type_resolve_state_tag;
CompilerType clang_type = m_ast.GetTypeForIdentifier<clang::CXXRecordDecl>(
ConstString(name), decl_context);
if (!clang_type.IsValid()) {
auto access = GetAccessibilityForUdt(*udt);
ClangASTMetadata metadata;
metadata.SetUserID(type.getSymIndexId());
metadata.SetIsDynamicCXXType(false);
auto tag_type_kind = TranslateUdtKind(udt->getUdtKind());
CompilerType clang_type = m_ast.CreateRecordType(
tu_decl_ctx, access, udt->getName().c_str(), tag_type_kind,
lldb::eLanguageTypeC_plus_plus, &metadata);
assert(clang_type.IsValid());
ClangASTMetadata metadata;
metadata.SetUserID(type.getSymIndexId());
metadata.SetIsDynamicCXXType(false);
clang_type = m_ast.CreateRecordType(
decl_context, access, name.c_str(), tag_type_kind,
lldb::eLanguageTypeC_plus_plus, &metadata);
assert(clang_type.IsValid());
auto record_decl =
m_ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType());
assert(record_decl);
m_uid_to_decl[type.getSymIndexId()] = record_decl;
auto inheritance_attr = clang::MSInheritanceAttr::CreateImplicit(
*m_ast.getASTContext(), GetMSInheritance(*udt));
record_decl->addAttr(inheritance_attr);
ClangASTContext::StartTagDeclarationDefinition(clang_type);
auto children = udt->findAllChildren();
if (!children || children->getChildCount() == 0) {
// PDB does not have symbol of forwarder. We assume we get an udt w/o
// any fields. Just complete it at this point.
ClangASTContext::CompleteTagDeclarationDefinition(clang_type);
ClangASTContext::SetHasExternalStorage(clang_type.GetOpaqueQualType(),
false);
type_resolve_state_tag = Type::eResolveStateFull;
} else {
// Add the type to the forward declarations. It will help us to avoid
// an endless recursion in CompleteTypeFromUdt function.
m_forward_decl_to_uid[record_decl] = type.getSymIndexId();
ClangASTContext::SetHasExternalStorage(clang_type.GetOpaqueQualType(),
true);
type_resolve_state_tag = Type::eResolveStateForward;
}
} else
type_resolve_state_tag = Type::eResolveStateForward;
if (udt->isConstType())
clang_type = clang_type.AddConstModifier();
@ -326,83 +406,73 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) {
if (udt->isVolatileType())
clang_type = clang_type.AddVolatileModifier();
clang::CXXRecordDecl *record_decl =
m_ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType());
assert(record_decl);
auto inheritance_attr = clang::MSInheritanceAttr::CreateImplicit(
*m_ast.getASTContext(), GetMSInheritance(*udt));
record_decl->addAttr(inheritance_attr);
ClangASTContext::StartTagDeclarationDefinition(clang_type);
Type::ResolveStateTag type_resolve_state_tag;
auto children = udt->findAllChildren();
if (!children || children->getChildCount() == 0) {
// PDB does not have symbol of forwarder. We assume we get an udt w/o any
// fields. Just complete it at this point.
ClangASTContext::CompleteTagDeclarationDefinition(clang_type);
m_ast.SetHasExternalStorage(clang_type.GetOpaqueQualType(), false);
type_resolve_state_tag = Type::eResolveStateFull;
} else {
// Add the type to the forward declarations. It will help us to avoid
// an endless recursion in CompleteTypeFromUdt function.
auto clang_type_removed_fast_quals =
ClangUtil::RemoveFastQualifiers(clang_type).GetOpaqueQualType();
m_forward_decl_clang_type_to_uid[clang_type_removed_fast_quals] =
type.getSymIndexId();
m_ast.SetHasExternalStorage(clang_type.GetOpaqueQualType(), true);
type_resolve_state_tag = Type::eResolveStateForward;
}
GetDeclarationForSymbol(type, decl);
return std::make_shared<lldb_private::Type>(
type.getSymIndexId(), m_ast.GetSymbolFile(),
ConstString(udt->getName()), udt->getLength(), nullptr,
LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, clang_type,
type.getSymIndexId(), m_ast.GetSymbolFile(), ConstString(name),
udt->getLength(), nullptr, LLDB_INVALID_UID,
lldb_private::Type::eEncodingIsUID, decl, clang_type,
type_resolve_state_tag);
} break;
case PDB_SymType::Enum: {
auto enum_type = llvm::dyn_cast<PDBSymbolTypeEnum>(&type);
assert(enum_type);
auto underlying_type_up = enum_type->getUnderlyingType();
if (!underlying_type_up)
return nullptr;
lldb::Encoding encoding =
TranslateBuiltinEncoding(underlying_type_up->getBuiltinType());
// FIXME: Type of underlying builtin is always `Int`. We correct it with
// the very first enumerator's encoding if any.
auto first_child = enum_type->findOneChild<PDBSymbolData>();
if (first_child) {
encoding = TranslateEnumEncoding(first_child->getValue().Type);
}
std::string name = enum_type->getName();
uint64_t bytes = enum_type->getLength();
CompilerType builtin_type;
if (bytes > 0)
builtin_type = GetBuiltinTypeForPDBEncodingAndBitSize(
m_ast, *underlying_type_up, encoding, bytes * 8);
else
builtin_type = m_ast.GetBasicType(eBasicTypeInt);
// FIXME: PDB does not have information about scoped enumeration (Enum
// Class). Set it false for now.
bool isScoped = false;
CompilerType ast_enum = m_ast.CreateEnumerationType(
name.c_str(), tu_decl_ctx, decl, builtin_type, isScoped);
auto enum_values = enum_type->findAllChildren<PDBSymbolData>();
if (enum_values) {
while (auto enum_value = enum_values->getNext()) {
if (enum_value->getDataKind() != PDB_DataKind::Constant)
continue;
AddEnumValue(ast_enum, *enum_value);
std::string name = PDBNameDropScope(enum_type->getName());
auto decl_context = GetDeclContextContainingSymbol(type);
uint64_t bytes = enum_type->getLength();
// Check if such an enum already exists in the current context
CompilerType ast_enum = m_ast.GetTypeForIdentifier<clang::EnumDecl>(
ConstString(name), decl_context);
if (!ast_enum.IsValid()) {
auto underlying_type_up = enum_type->getUnderlyingType();
if (!underlying_type_up)
return nullptr;
lldb::Encoding encoding =
TranslateBuiltinEncoding(underlying_type_up->getBuiltinType());
// FIXME: Type of underlying builtin is always `Int`. We correct it with
// the very first enumerator's encoding if any.
auto first_child = enum_type->findOneChild<PDBSymbolData>();
if (first_child)
encoding = TranslateEnumEncoding(first_child->getValue().Type);
CompilerType builtin_type;
if (bytes > 0)
builtin_type = GetBuiltinTypeForPDBEncodingAndBitSize(
m_ast, *underlying_type_up, encoding, bytes * 8);
else
builtin_type = m_ast.GetBasicType(eBasicTypeInt);
// FIXME: PDB does not have information about scoped enumeration (Enum
// Class). Set it false for now.
bool isScoped = false;
ast_enum = m_ast.CreateEnumerationType(name.c_str(), decl_context, decl,
builtin_type, isScoped);
auto enum_decl = ClangASTContext::GetAsEnumDecl(ast_enum);
assert(enum_decl);
m_uid_to_decl[type.getSymIndexId()] = enum_decl;
auto enum_values = enum_type->findAllChildren<PDBSymbolData>();
if (enum_values) {
while (auto enum_value = enum_values->getNext()) {
if (enum_value->getDataKind() != PDB_DataKind::Constant)
continue;
AddEnumValue(ast_enum, *enum_value);
}
}
if (ClangASTContext::StartTagDeclarationDefinition(ast_enum))
ClangASTContext::CompleteTagDeclarationDefinition(ast_enum);
}
if (ClangASTContext::StartTagDeclarationDefinition(ast_enum))
ClangASTContext::CompleteTagDeclarationDefinition(ast_enum);
if (enum_type->isConstType())
ast_enum = ast_enum.AddConstModifier();
if (enum_type->isVolatileType())
ast_enum = ast_enum.AddVolatileModifier();
GetDeclarationForSymbol(type, decl);
return std::make_shared<lldb_private::Type>(
@ -413,23 +483,42 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) {
case PDB_SymType::Typedef: {
auto type_def = llvm::dyn_cast<PDBSymbolTypeTypedef>(&type);
assert(type_def);
lldb_private::Type *target_type =
m_ast.GetSymbolFile()->ResolveTypeUID(type_def->getTypeId());
if (!target_type)
return nullptr;
std::string name = type_def->getName();
uint64_t bytes = type_def->getLength();
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);
if (!ast_typedef)
return nullptr;
std::string name = PDBNameDropScope(type_def->getName());
auto decl_ctx = GetDeclContextContainingSymbol(type);
// Check if such a typedef already exists in the current context
CompilerType ast_typedef =
m_ast.GetTypeForIdentifier<clang::TypedefNameDecl>(ConstString(name),
decl_ctx);
if (!ast_typedef.IsValid()) {
CompilerType target_ast_type = target_type->GetFullCompilerType();
ast_typedef = m_ast.CreateTypedefType(
target_ast_type, name.c_str(), CompilerDeclContext(&m_ast, decl_ctx));
if (!ast_typedef)
return nullptr;
auto typedef_decl = ClangASTContext::GetAsTypedefDecl(ast_typedef);
assert(typedef_decl);
m_uid_to_decl[type.getSymIndexId()] = typedef_decl;
}
if (type_def->isConstType())
ast_typedef = ast_typedef.AddConstModifier();
if (type_def->isVolatileType())
ast_typedef = ast_typedef.AddVolatileModifier();
GetDeclarationForSymbol(type, decl);
return std::make_shared<lldb_private::Type>(
type_def->getSymIndexId(), m_ast.GetSymbolFile(), ConstString(name),
bytes, nullptr, target_type->GetID(),
type_def->getLength(), nullptr, target_type->GetID(),
lldb_private::Type::eEncodingIsTypedefUID, decl, ast_typedef,
lldb_private::Type::eResolveStateFull);
} break;
@ -446,7 +535,7 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) {
return nullptr;
func_sig = sig.release();
// Function type is named.
name = pdb_func->getName();
name = PDBNameDropScope(pdb_func->getName());
} else if (auto pdb_func_sig =
llvm::dyn_cast<PDBSymbolTypeFunctionSig>(&type)) {
func_sig = const_cast<PDBSymbolTypeFunctionSig *>(pdb_func_sig);
@ -623,11 +712,10 @@ bool PDBASTParser::CompleteTypeFromPDB(
// Remove the type from the forward declarations to avoid
// an endless recursion for types like a linked list.
CompilerType compiler_type_no_qualifiers =
ClangUtil::RemoveFastQualifiers(compiler_type);
auto uid_it = m_forward_decl_clang_type_to_uid.find(
compiler_type_no_qualifiers.GetOpaqueQualType());
if (uid_it == m_forward_decl_clang_type_to_uid.end())
clang::CXXRecordDecl *record_decl =
m_ast.GetAsCXXRecordDecl(compiler_type.GetOpaqueQualType());
auto uid_it = m_forward_decl_to_uid.find(record_decl);
if (uid_it == m_forward_decl_to_uid.end())
return true;
auto symbol_file = static_cast<SymbolFilePDB *>(m_ast.GetSymbolFile());
@ -639,7 +727,7 @@ bool PDBASTParser::CompleteTypeFromPDB(
if (!symbol)
return false;
m_forward_decl_clang_type_to_uid.erase(uid_it);
m_forward_decl_to_uid.erase(uid_it);
ClangASTContext::SetHasExternalStorage(compiler_type.GetOpaqueQualType(),
false);
@ -657,11 +745,265 @@ bool PDBASTParser::CompleteTypeFromPDB(
}
}
clang::Decl *
PDBASTParser::GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol) {
auto it = m_uid_to_decl.find(symbol.getSymIndexId());
if (it != m_uid_to_decl.end())
return it->second;
auto symbol_file = static_cast<SymbolFilePDB *>(m_ast.GetSymbolFile());
if (!symbol_file)
return nullptr;
// First of all, check if the symbol is a member of a class. Resolve the full
// class type and return the declaration from the cache if so.
auto tag = symbol.getSymTag();
if (tag == PDB_SymType::Data || tag == PDB_SymType::Function) {
const IPDBSession &session = symbol.getSession();
const IPDBRawSymbol &raw = symbol.getRawSymbol();
auto class_parent_id = raw.getClassParentId();
if (session.getSymbolById(class_parent_id)) {
auto class_parent_type = symbol_file->ResolveTypeUID(class_parent_id);
if (!class_parent_type)
return nullptr;
class_parent_type->GetFullCompilerType();
return m_uid_to_decl.lookup(symbol.getSymIndexId());
}
}
// If we are here, then the symbol is not belonging to a class and is not
// contained in the cache. So create a declaration for it.
switch (symbol.getSymTag()) {
case PDB_SymType::Data: {
auto data = llvm::dyn_cast<PDBSymbolData>(&symbol);
assert(data);
auto decl_context = GetDeclContextContainingSymbol(symbol);
assert(decl_context);
// May be the current context is a class really, but we haven't found
// any class parent. This happens e.g. in the case of class static
// variables - they has two symbols, one is a child of the class when
// another is a child of the exe. So always complete the parent and use
// an existing declaration if possible.
if (auto parent_decl = llvm::dyn_cast_or_null<clang::TagDecl>(decl_context))
m_ast.GetCompleteDecl(parent_decl);
auto name = PDBNameDropScope(data->getName());
// Check if the current context already contains the symbol with the name.
clang::Decl *decl =
GetDeclFromContextByName(*m_ast.getASTContext(), *decl_context, name);
if (!decl) {
auto type = symbol_file->ResolveTypeUID(data->getTypeId());
if (!type)
return nullptr;
decl = m_ast.CreateVariableDeclaration(
decl_context, name.c_str(),
ClangUtil::GetQualType(type->GetLayoutCompilerType()));
}
m_uid_to_decl[data->getSymIndexId()] = decl;
return decl;
}
case PDB_SymType::Function: {
auto func = llvm::dyn_cast<PDBSymbolFunc>(&symbol);
assert(func);
auto decl_context = GetDeclContextContainingSymbol(symbol);
assert(decl_context);
auto name = PDBNameDropScope(func->getName());
auto type = symbol_file->ResolveTypeUID(func->getSymIndexId());
if (!type)
return nullptr;
auto storage = func->isStatic() ? clang::StorageClass::SC_Static
: clang::StorageClass::SC_None;
auto decl = m_ast.CreateFunctionDeclaration(
decl_context, name.c_str(), type->GetForwardCompilerType(), storage,
func->hasInlineAttribute());
m_uid_to_decl[func->getSymIndexId()] = decl;
return decl;
}
default: {
// It's not a variable and not a function, check if it's a type
auto type = symbol_file->ResolveTypeUID(symbol.getSymIndexId());
if (!type)
return nullptr;
return m_uid_to_decl.lookup(symbol.getSymIndexId());
}
}
}
clang::DeclContext *
PDBASTParser::GetDeclContextForSymbol(const llvm::pdb::PDBSymbol &symbol) {
if (symbol.getSymTag() == PDB_SymType::Function) {
clang::DeclContext *result =
llvm::dyn_cast_or_null<clang::FunctionDecl>(GetDeclForSymbol(symbol));
if (result)
m_decl_context_to_uid[result] = symbol.getSymIndexId();
return result;
}
auto symbol_file = static_cast<SymbolFilePDB *>(m_ast.GetSymbolFile());
if (!symbol_file)
return nullptr;
auto type = symbol_file->ResolveTypeUID(symbol.getSymIndexId());
if (!type)
return nullptr;
clang::DeclContext *result =
m_ast.GetDeclContextForType(type->GetForwardCompilerType());
if (result)
m_decl_context_to_uid[result] = symbol.getSymIndexId();
return result;
}
clang::DeclContext *PDBASTParser::GetDeclContextContainingSymbol(
const llvm::pdb::PDBSymbol &symbol) {
auto parent = GetClassOrFunctionParent(symbol);
while (parent) {
if (auto parent_context = GetDeclContextForSymbol(*parent))
return parent_context;
parent = GetClassOrFunctionParent(*parent);
}
// We can't find any class or function parent of the symbol. So analyze
// the full symbol name. The symbol may be belonging to a namespace
// or function (or even to a class if it's e.g. a static variable symbol).
// We do not use CPlusPlusNameParser because it fails on things like
// `anonymous namespace'.
// TODO: Make clang to emit full names for variables in namespaces
// (as MSVC does)
auto context = symbol.getRawSymbol().getName();
auto context_size = context.rfind("::");
if (context_size == std::string::npos)
context_size = 0;
context = context.substr(0, context_size);
// Check if there is a symbol with the name of the context.
auto symbol_file = static_cast<SymbolFilePDB *>(m_ast.GetSymbolFile());
if (!symbol_file)
return m_ast.GetTranslationUnitDecl();
auto global = symbol_file->GetPDBSession().getGlobalScope();
if (!global)
return m_ast.GetTranslationUnitDecl();
TypeMap types;
if (auto children_enum =
global->findChildren(PDB_SymType::None, context, NS_CaseSensitive))
while (auto child = children_enum->getNext())
if (auto child_context = GetDeclContextForSymbol(*child))
return child_context;
// Split context and retrieve nested namespaces
auto curr_context = m_ast.GetTranslationUnitDecl();
auto from = 0;
while (from < context_size) {
auto to = context.find("::", from);
if (to == std::string::npos)
to = context_size;
auto namespace_name = context.substr(from, to - from);
auto namespace_name_c_str = IsAnonymousNamespaceName(namespace_name)
? nullptr
: namespace_name.c_str();
auto namespace_decl =
m_ast.GetUniqueNamespaceDeclaration(namespace_name_c_str, curr_context);
m_parent_to_namespaces[curr_context].insert(namespace_decl);
curr_context = namespace_decl;
from = to + 2;
}
return curr_context;
}
void PDBASTParser::ParseDeclsForDeclContext(
const clang::DeclContext *decl_context) {
auto symbol_file = static_cast<SymbolFilePDB *>(m_ast.GetSymbolFile());
if (!symbol_file)
return;
IPDBSession &session = symbol_file->GetPDBSession();
auto symbol_up =
session.getSymbolById(m_decl_context_to_uid.lookup(decl_context));
auto global_up = session.getGlobalScope();
PDBSymbol *symbol;
if (symbol_up)
symbol = symbol_up.get();
else if (global_up)
symbol = global_up.get();
else
return;
if (auto children = symbol->findAllChildren())
while (auto child = children->getNext())
GetDeclForSymbol(*child);
}
clang::NamespaceDecl *
PDBASTParser::FindNamespaceDecl(const clang::DeclContext *parent,
llvm::StringRef name) {
if (!parent)
parent = m_ast.GetTranslationUnitDecl();
auto it = m_parent_to_namespaces.find(parent);
if (it == m_parent_to_namespaces.end())
return nullptr;
for (auto namespace_decl : it->second)
if (namespace_decl->getName().equals(name))
return namespace_decl;
for (auto namespace_decl : it->second)
if (namespace_decl->isAnonymousNamespace())
return FindNamespaceDecl(namespace_decl, name);
return nullptr;
}
std::string PDBASTParser::PDBNameDropScope(const std::string &name) {
// Not all PDB names can be parsed with CPlusPlusNameParser.
// E.g. it fails on names containing `anonymous namespace'.
// So we simply drop everything before '::'
auto offset = name.rfind("::");
if (offset == std::string::npos)
return name;
assert(offset + 2 <= name.size());
return name.substr(offset + 2);
}
bool PDBASTParser::AddEnumValue(CompilerType enum_type,
const PDBSymbolData &enum_value) const {
const PDBSymbolData &enum_value) {
Declaration decl;
Variant v = enum_value.getValue();
std::string name = enum_value.getName();
std::string name = PDBNameDropScope(enum_value.getName());
int64_t raw_value;
switch (v.Type) {
case PDB_VariantType::Int8:
@ -695,9 +1037,15 @@ bool PDBASTParser::AddEnumValue(CompilerType enum_type,
m_ast.GetEnumerationIntegerType(enum_type.GetOpaqueQualType());
uint32_t byte_size = m_ast.getASTContext()->getTypeSize(
ClangUtil::GetQualType(underlying_type));
return m_ast.AddEnumerationValueToEnumerationType(
auto enum_constant_decl = m_ast.AddEnumerationValueToEnumerationType(
enum_type.GetOpaqueQualType(), underlying_type, decl, name.c_str(),
raw_value, byte_size * 8);
if (!enum_constant_decl)
return false;
m_uid_to_decl[enum_value.getSymIndexId()] = enum_constant_decl;
return true;
}
bool PDBASTParser::CompleteTypeFromUDT(
@ -744,10 +1092,10 @@ void PDBASTParser::AddRecordMembers(
lldb_private::SymbolFile &symbol_file,
lldb_private::CompilerType &record_type,
PDBDataSymbolEnumerator &members_enum,
lldb_private::ClangASTImporter::LayoutInfo &layout_info) const {
lldb_private::ClangASTImporter::LayoutInfo &layout_info) {
while (auto member = members_enum.getNext()) {
if (member->isCompilerGenerated())
continue;
continue;
auto member_name = member->getName();
@ -781,6 +1129,8 @@ void PDBASTParser::AddRecordMembers(
if (!decl)
continue;
m_uid_to_decl[member->getSymIndexId()] = decl;
auto offset = member->getOffset() * 8;
if (location_type == PDB_LocType::BitField)
offset += member->getBitPosition();
@ -789,10 +1139,16 @@ void PDBASTParser::AddRecordMembers(
break;
}
case PDB_DataKind::StaticMember:
ClangASTContext::AddVariableToRecordType(record_type, member_name.c_str(),
member_comp_type, access);
case PDB_DataKind::StaticMember: {
auto decl = ClangASTContext::AddVariableToRecordType(
record_type, member_name.c_str(), member_comp_type, access);
if (!decl)
continue;
m_uid_to_decl[member->getSymIndexId()] = decl;
break;
}
default:
llvm_unreachable("unsupported PDB data kind");
}
@ -829,12 +1185,12 @@ void PDBASTParser::AddRecordBases(
base_comp_type.GetOpaqueQualType(), access, is_virtual,
record_kind == clang::TTK_Class);
if (!base_class_spec)
continue;
continue;
base_classes.push_back(base_class_spec);
if (is_virtual)
continue;
continue;
auto decl = m_ast.GetAsCXXRecordDecl(base_comp_type.GetOpaqueQualType());
if (!decl)
@ -852,15 +1208,16 @@ void PDBASTParser::AddRecordBases(
}
}
void PDBASTParser::AddRecordMethods(
lldb_private::SymbolFile &symbol_file,
lldb_private::CompilerType &record_type,
PDBFuncSymbolEnumerator &methods_enum) const {
void PDBASTParser::AddRecordMethods(lldb_private::SymbolFile &symbol_file,
lldb_private::CompilerType &record_type,
PDBFuncSymbolEnumerator &methods_enum) {
while (auto method = methods_enum.getNext()) {
auto name = PDBNameDropScope(method->getName().c_str());
auto method_type = symbol_file.ResolveTypeUID(method->getSymIndexId());
// MSVC specific __vecDelDtor.
if (!method_type)
break;
continue;
auto method_comp_type = method_type->GetFullCompilerType();
if (!method_comp_type.GetCompleteType()) {
@ -873,13 +1230,17 @@ void PDBASTParser::AddRecordMethods(
}
// TODO: get mangled name for the method.
m_ast.AddMethodToCXXRecordType(
record_type.GetOpaqueQualType(), method->getName().c_str(),
auto decl = m_ast.AddMethodToCXXRecordType(
record_type.GetOpaqueQualType(), name.c_str(),
/*mangled_name*/ nullptr, method_comp_type,
TranslateMemberAccess(method->getAccess()), method->isVirtual(),
method->isStatic(), method->hasInlineAttribute(),
/*is_explicit*/ false, // FIXME: Need this field in CodeView.
/*is_attr_used*/ false,
/*is_artificial*/ method->isCompilerGenerated());
if (!decl)
continue;
m_uid_to_decl[method->getSymIndexId()] = decl;
}
}

View File

@ -14,6 +14,8 @@
#include "lldb/Symbol/ClangASTImporter.h"
class SymbolFilePDB;
namespace clang {
class CharUnits;
class CXXRecordDecl;
@ -47,13 +49,32 @@ public:
lldb::TypeSP CreateLLDBTypeFromPDBType(const llvm::pdb::PDBSymbol &type);
bool CompleteTypeFromPDB(lldb_private::CompilerType &compiler_type);
clang::Decl *GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol);
clang::DeclContext *
GetDeclContextForSymbol(const llvm::pdb::PDBSymbol &symbol);
clang::DeclContext *
GetDeclContextContainingSymbol(const llvm::pdb::PDBSymbol &symbol);
void ParseDeclsForDeclContext(const clang::DeclContext *decl_context);
clang::NamespaceDecl *FindNamespaceDecl(const clang::DeclContext *parent,
llvm::StringRef name);
lldb_private::ClangASTImporter &GetClangASTImporter() {
return m_ast_importer;
}
static std::string PDBNameDropScope(const std::string &name);
private:
typedef llvm::DenseMap<lldb::opaque_compiler_type_t, lldb::user_id_t>
ClangTypeToUidMap;
typedef llvm::DenseMap<clang::CXXRecordDecl *, lldb::user_id_t>
CXXRecordDeclToUidMap;
typedef llvm::DenseMap<lldb::user_id_t, clang::Decl *> UidToDeclMap;
typedef llvm::DenseMap<clang::DeclContext *, std::set<clang::NamespaceDecl *>>
ParentToNamespacesMap;
typedef llvm::DenseMap<clang::DeclContext *, lldb::user_id_t>
DeclContextToUidMap;
typedef llvm::pdb::ConcreteSymbolEnumerator<llvm::pdb::PDBSymbolData>
PDBDataSymbolEnumerator;
typedef llvm::pdb::ConcreteSymbolEnumerator<llvm::pdb::PDBSymbolTypeBaseClass>
@ -62,29 +83,31 @@ private:
PDBFuncSymbolEnumerator;
bool AddEnumValue(lldb_private::CompilerType enum_type,
const llvm::pdb::PDBSymbolData &data) const;
const llvm::pdb::PDBSymbolData &data);
bool CompleteTypeFromUDT(lldb_private::SymbolFile &symbol_file,
lldb_private::CompilerType &compiler_type,
llvm::pdb::PDBSymbolTypeUDT &udt);
void AddRecordMembers(
lldb_private::SymbolFile &symbol_file,
lldb_private::CompilerType &record_type,
PDBDataSymbolEnumerator &members_enum,
lldb_private::ClangASTImporter::LayoutInfo &layout_info) const;
void AddRecordBases(
lldb_private::SymbolFile &symbol_file,
lldb_private::CompilerType &record_type,
int record_kind,
PDBBaseClassSymbolEnumerator &bases_enum,
lldb_private::ClangASTImporter::LayoutInfo &layout_info) const;
void AddRecordMethods(
lldb_private::SymbolFile &symbol_file,
lldb_private::CompilerType &record_type,
PDBFuncSymbolEnumerator &methods_enum) const;
void
AddRecordMembers(lldb_private::SymbolFile &symbol_file,
lldb_private::CompilerType &record_type,
PDBDataSymbolEnumerator &members_enum,
lldb_private::ClangASTImporter::LayoutInfo &layout_info);
void
AddRecordBases(lldb_private::SymbolFile &symbol_file,
lldb_private::CompilerType &record_type, int record_kind,
PDBBaseClassSymbolEnumerator &bases_enum,
lldb_private::ClangASTImporter::LayoutInfo &layout_info) const;
void AddRecordMethods(lldb_private::SymbolFile &symbol_file,
lldb_private::CompilerType &record_type,
PDBFuncSymbolEnumerator &methods_enum);
lldb_private::ClangASTContext &m_ast;
lldb_private::ClangASTImporter m_ast_importer;
ClangTypeToUidMap m_forward_decl_clang_type_to_uid;
CXXRecordDeclToUidMap m_forward_decl_to_uid;
UidToDeclMap m_uid_to_decl;
ParentToNamespacesMap m_parent_to_namespaces;
DeclContextToUidMap m_decl_context_to_uid;
};
#endif // LLDB_PLUGINS_SYMBOLFILE_PDB_PDBASTPARSER_H

View File

@ -551,8 +551,7 @@ lldb_private::Type *SymbolFilePDB::ResolveTypeUID(lldb::user_id_t type_uid) {
llvm::dyn_cast_or_null<ClangASTContext>(type_system);
if (!clang_type_system)
return nullptr;
PDBASTParser *pdb =
llvm::dyn_cast<PDBASTParser>(clang_type_system->GetPDBParser());
PDBASTParser *pdb = clang_type_system->GetPDBParser();
if (!pdb)
return nullptr;
@ -579,8 +578,7 @@ bool SymbolFilePDB::CompleteType(lldb_private::CompilerType &compiler_type) {
if (!clang_ast_ctx)
return false;
PDBASTParser *pdb =
llvm::dyn_cast<PDBASTParser>(clang_ast_ctx->GetPDBParser());
PDBASTParser *pdb = clang_ast_ctx->GetPDBParser();
if (!pdb)
return false;
@ -588,24 +586,83 @@ bool SymbolFilePDB::CompleteType(lldb_private::CompilerType &compiler_type) {
}
lldb_private::CompilerDecl SymbolFilePDB::GetDeclForUID(lldb::user_id_t uid) {
return lldb_private::CompilerDecl();
ClangASTContext *clang_ast_ctx = llvm::dyn_cast_or_null<ClangASTContext>(
GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus));
if (!clang_ast_ctx)
return CompilerDecl();
PDBASTParser *pdb = clang_ast_ctx->GetPDBParser();
if (!pdb)
return CompilerDecl();
auto symbol = m_session_up->getSymbolById(uid);
if (!symbol)
return CompilerDecl();
auto decl = pdb->GetDeclForSymbol(*symbol);
if (!decl)
return CompilerDecl();
return CompilerDecl(clang_ast_ctx, decl);
}
lldb_private::CompilerDeclContext
SymbolFilePDB::GetDeclContextForUID(lldb::user_id_t uid) {
// 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;
ClangASTContext *clang_ast_ctx = llvm::dyn_cast_or_null<ClangASTContext>(
GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus));
if (!clang_ast_ctx)
return CompilerDeclContext();
PDBASTParser *pdb = clang_ast_ctx->GetPDBParser();
if (!pdb)
return CompilerDeclContext();
auto symbol = m_session_up->getSymbolById(uid);
if (!symbol)
return CompilerDeclContext();
auto decl_context = pdb->GetDeclContextForSymbol(*symbol);
if (!decl_context)
return GetDeclContextContainingUID(uid);
return CompilerDeclContext(clang_ast_ctx, decl_context);
}
lldb_private::CompilerDeclContext
SymbolFilePDB::GetDeclContextContainingUID(lldb::user_id_t uid) {
return *m_tu_decl_ctx_up;
ClangASTContext *clang_ast_ctx = llvm::dyn_cast_or_null<ClangASTContext>(
GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus));
if (!clang_ast_ctx)
return CompilerDeclContext();
PDBASTParser *pdb = clang_ast_ctx->GetPDBParser();
if (!pdb)
return CompilerDeclContext();
auto symbol = m_session_up->getSymbolById(uid);
if (!symbol)
return CompilerDeclContext();
auto decl_context = pdb->GetDeclContextContainingSymbol(*symbol);
assert(decl_context);
return CompilerDeclContext(clang_ast_ctx, decl_context);
}
void SymbolFilePDB::ParseDeclsForContext(
lldb_private::CompilerDeclContext decl_ctx) {}
lldb_private::CompilerDeclContext decl_ctx) {
ClangASTContext *clang_ast_ctx = llvm::dyn_cast_or_null<ClangASTContext>(
GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus));
if (!clang_ast_ctx)
return;
PDBASTParser *pdb = clang_ast_ctx->GetPDBParser();
if (!pdb)
return;
pdb->ParseDeclsForDeclContext(
static_cast<clang::DeclContext *>(decl_ctx.GetOpaqueDeclContext()));
}
uint32_t
SymbolFilePDB::ResolveSymbolContext(const lldb_private::Address &so_addr,
@ -876,7 +933,7 @@ VariableSP SymbolFilePDB::ParseVariableForPDBData(
if (scope == eValueTypeVariableLocal) {
if (sc.function) {
context_scope = sc.function->GetBlock(true).FindBlockByID(
pdb_data.getClassParentId());
pdb_data.getLexicalParentId());
if (context_scope == nullptr)
context_scope = sc.function;
}
@ -973,14 +1030,14 @@ uint32_t SymbolFilePDB::FindGlobalVariables(
const lldb_private::ConstString &name,
const lldb_private::CompilerDeclContext *parent_decl_ctx,
uint32_t max_matches, lldb_private::VariableList &variables) {
if (!parent_decl_ctx)
parent_decl_ctx = m_tu_decl_ctx_up.get();
if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx))
return 0;
if (name.IsEmpty())
return 0;
auto results =
m_global_scope_up->findChildren(PDB_SymType::Data, name.GetStringRef(),
PDB_NameSearchFlags::NS_CaseSensitive);
auto results = m_global_scope_up->findAllChildren<PDBSymbolData>();
if (!results)
return 0;
@ -1000,6 +1057,15 @@ uint32_t SymbolFilePDB::FindGlobalVariables(
if (sc.comp_unit == nullptr)
continue;
if (!name.GetStringRef().equals(
PDBASTParser::PDBNameDropScope(pdb_data->getName())))
continue;
auto actual_parent_decl_ctx =
GetDeclContextContainingUID(result->getSymIndexId());
if (actual_parent_decl_ctx != *parent_decl_ctx)
continue;
ParseVariables(sc, *pdb_data, &variables);
matches = variables.GetSize() - old_size;
}
@ -1275,7 +1341,7 @@ uint32_t SymbolFilePDB::FindTypes(
std::string name_str = name.AsCString();
// There is an assumption 'name' is not a regex
FindTypesByName(name_str, max_matches, types);
FindTypesByName(name_str, parent_decl_ctx, max_matches, types);
return types.GetSize();
}
@ -1335,14 +1401,16 @@ void SymbolFilePDB::FindTypesByRegex(
}
}
void SymbolFilePDB::FindTypesByName(const std::string &name,
uint32_t max_matches,
lldb_private::TypeMap &types) {
void SymbolFilePDB::FindTypesByName(
const std::string &name,
const lldb_private::CompilerDeclContext *parent_decl_ctx,
uint32_t max_matches, lldb_private::TypeMap &types) {
if (!parent_decl_ctx)
parent_decl_ctx = m_tu_decl_ctx_up.get();
std::unique_ptr<IPDBEnumSymbols> results;
if (name.empty())
return;
results = m_global_scope_up->findChildren(PDB_SymType::None, name,
PDB_NameSearchFlags::NS_Default);
results = m_global_scope_up->findAllChildren(PDB_SymType::None);
if (!results)
return;
@ -1351,6 +1419,11 @@ void SymbolFilePDB::FindTypesByName(const std::string &name,
while (auto result = results->getNext()) {
if (max_matches > 0 && matches >= max_matches)
break;
if (PDBASTParser::PDBNameDropScope(result->getRawSymbol().getName()) !=
name)
continue;
switch (result->getSymTag()) {
case PDB_SymType::Enum:
case PDB_SymType::UDT:
@ -1367,6 +1440,11 @@ void SymbolFilePDB::FindTypesByName(const std::string &name,
if (!ResolveTypeUID(result->getSymIndexId()))
continue;
auto actual_parent_decl_ctx =
GetDeclContextContainingUID(result->getSymIndexId());
if (actual_parent_decl_ctx != *parent_decl_ctx)
continue;
auto iter = m_types.find(result->getSymIndexId());
if (iter == m_types.end())
continue;
@ -1477,7 +1555,27 @@ lldb_private::CompilerDeclContext SymbolFilePDB::FindNamespace(
const lldb_private::SymbolContext &sc,
const lldb_private::ConstString &name,
const lldb_private::CompilerDeclContext *parent_decl_ctx) {
return lldb_private::CompilerDeclContext();
auto type_system = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
auto clang_type_system = llvm::dyn_cast_or_null<ClangASTContext>(type_system);
if (!clang_type_system)
return CompilerDeclContext();
PDBASTParser *pdb = clang_type_system->GetPDBParser();
if (!pdb)
return CompilerDeclContext();
clang::DeclContext *decl_context = nullptr;
if (parent_decl_ctx)
decl_context = static_cast<clang::DeclContext *>(
parent_decl_ctx->GetOpaqueDeclContext());
auto namespace_decl =
pdb->FindNamespaceDecl(decl_context, name.GetStringRef());
if (!namespace_decl)
return CompilerDeclContext();
return CompilerDeclContext(type_system,
static_cast<clang::DeclContext *>(namespace_decl));
}
lldb_private::ConstString SymbolFilePDB::GetPluginName() {

View File

@ -179,8 +179,9 @@ private:
const llvm::pdb::PDBSymbolCompiland &pdb_compiland,
llvm::DenseMap<uint32_t, uint32_t> &index_map) const;
void FindTypesByName(const std::string &name, uint32_t max_matches,
lldb_private::TypeMap &types);
void FindTypesByName(const std::string &name,
const lldb_private::CompilerDeclContext *parent_decl_ctx,
uint32_t max_matches, lldb_private::TypeMap &types);
std::string GetMangledForPDBData(const llvm::pdb::PDBSymbolData &pdb_data);

View File

@ -2212,6 +2212,9 @@ ClangASTContext::CreateEnumerationType(const char *name, DeclContext *decl_ctx,
false); // IsFixed
if (enum_decl) {
if (decl_ctx)
decl_ctx->addDecl(enum_decl);
// TODO: check if we should be setting the promotion type too?
enum_decl->setIntegerType(ClangUtil::GetQualType(integer_clang_type));
@ -4739,6 +4742,8 @@ CompilerType ClangASTContext::CreateTypedefType(
decl->setAccess(clang::AS_public); // TODO respect proper access specifier
decl_ctx->addDecl(decl);
// Get a uniqued clang::QualType for the typedef decl type
return CompilerType(clang_ast, clang_ast->getTypedefType(decl));
}
@ -7746,6 +7751,15 @@ clang::TagDecl *ClangASTContext::GetAsTagDecl(const CompilerType &type) {
return qual_type->getAsTagDecl();
}
clang::TypedefNameDecl *
ClangASTContext::GetAsTypedefDecl(const CompilerType &type) {
const clang::TypedefType *typedef_type =
llvm::dyn_cast<clang::TypedefType>(ClangUtil::GetQualType(type));
if (typedef_type)
return typedef_type->getDecl();
return nullptr;
}
clang::CXXRecordDecl *
ClangASTContext::GetAsCXXRecordDecl(lldb::opaque_compiler_type_t type) {
return GetCanonicalQualType(type)->getAsCXXRecordDecl();
@ -8831,7 +8845,7 @@ bool ClangASTContext::CompleteTagDeclarationDefinition(
return false;
}
bool ClangASTContext::AddEnumerationValueToEnumerationType(
clang::EnumConstantDecl *ClangASTContext::AddEnumerationValueToEnumerationType(
lldb::opaque_compiler_type_t type,
const CompilerType &enumerator_clang_type, const Declaration &decl,
const char *name, int64_t enum_value, uint32_t enum_value_bit_size) {
@ -8863,12 +8877,12 @@ bool ClangASTContext::AddEnumerationValueToEnumerationType(
VerifyDecl(enumerator_decl);
#endif
return true;
return enumerator_decl;
}
}
}
}
return false;
return nullptr;
}
CompilerType

View File

@ -148,6 +148,10 @@ static FunctionNameType getFunctionNameFlags() {
return Result;
}
static cl::opt<bool> DumpAST("dump-ast",
cl::desc("Dump AST restored from symbols."),
cl::sub(SymbolsSubcommand));
static cl::opt<bool> Verify("verify", cl::desc("Verify symbol information."),
cl::sub(SymbolsSubcommand));
@ -165,6 +169,7 @@ static Error findNamespaces(lldb_private::Module &Module);
static Error findTypes(lldb_private::Module &Module);
static Error findVariables(lldb_private::Module &Module);
static Error dumpModule(lldb_private::Module &Module);
static Error dumpAST(lldb_private::Module &Module);
static Error verify(lldb_private::Module &Module);
static Expected<Error (*)(lldb_private::Module &)> getAction();
@ -509,6 +514,34 @@ Error opts::symbols::dumpModule(lldb_private::Module &Module) {
return Error::success();
}
Error opts::symbols::dumpAST(lldb_private::Module &Module) {
SymbolVendor &plugin = *Module.GetSymbolVendor();
auto symfile = plugin.GetSymbolFile();
if (!symfile)
return make_string_error("Module has no symbol file.");
auto clang_ast_ctx = llvm::dyn_cast_or_null<ClangASTContext>(
symfile->GetTypeSystemForLanguage(eLanguageTypeC_plus_plus));
if (!clang_ast_ctx)
return make_string_error("Can't retrieve Clang AST context.");
auto ast_ctx = clang_ast_ctx->getASTContext();
if (!ast_ctx)
return make_string_error("Can't retrieve AST context.");
auto tu = ast_ctx->getTranslationUnitDecl();
if (!tu)
return make_string_error("Can't retrieve translation unit declaration.");
symfile->ParseDeclsForContext(CompilerDeclContext(
clang_ast_ctx, static_cast<clang::DeclContext *>(tu)));
tu->print(outs());
return Error::success();
}
Error opts::symbols::verify(lldb_private::Module &Module) {
SymbolVendor &plugin = *Module.GetSymbolVendor();
@ -562,6 +595,10 @@ Error opts::symbols::verify(lldb_private::Module &Module) {
}
Expected<Error (*)(lldb_private::Module &)> opts::symbols::getAction() {
if (Verify && DumpAST)
return make_string_error(
"Cannot both verify symbol information and dump AST.");
if (Verify) {
if (Find != FindType::None)
return make_string_error(
@ -574,6 +611,18 @@ Expected<Error (*)(lldb_private::Module &)> opts::symbols::getAction() {
return verify;
}
if (DumpAST) {
if (Find != FindType::None)
return make_string_error(
"Cannot both search and dump AST.");
if (Regex || !Context.empty() || !Name.empty() || !File.empty() ||
Line != 0)
return make_string_error(
"-regex, -context, -name, -file and -line options are not "
"applicable for dumping AST.");
return dumpAST;
}
if (Regex && !Context.empty())
return make_string_error(
"Cannot search using both regular expressions and context.");
@ -632,6 +681,8 @@ Expected<Error (*)(lldb_private::Module &)> opts::symbols::getAction() {
"using line numbers.");
return findVariables;
}
llvm_unreachable("Unsupported symbol action.");
}
int opts::symbols::dumpSymbols(Debugger &Dbg) {