2018-10-23 17:22:02 +00:00

186 lines
6.7 KiB
C++

#include "UdtRecordCompleter.h"
#include "PdbIndex.h"
#include "PdbSymUid.h"
#include "PdbUtil.h"
#include "SymbolFileNativePDB.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/Type.h"
#include "lldb/Utility/LLDBAssert.h"
#include "lldb/lldb-enumerations.h"
#include "lldb/lldb-forward.h"
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
#include "llvm/DebugInfo/PDB/PDBTypes.h"
using namespace llvm::codeview;
using namespace llvm::pdb;
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::npdb;
using Error = llvm::Error;
UdtRecordCompleter::UdtRecordCompleter(PdbSymUid uid, CompilerType &derived_ct,
clang::TagDecl &tag_decl,
SymbolFileNativePDB &symbol_file)
: m_uid(uid), m_derived_ct(derived_ct), m_tag_decl(tag_decl),
m_symbol_file(symbol_file) {
TpiStream &tpi = symbol_file.m_index->tpi();
TypeIndex ti(uid.asTypeSym().index);
CVType cvt = tpi.getType(ti);
switch (cvt.kind()) {
case LF_ENUM:
lldbassert(uid.tag() == PDB_SymType::Enum);
llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, m_cvr.er));
break;
case LF_UNION:
lldbassert(uid.tag() == PDB_SymType::UDT);
llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, m_cvr.ur));
break;
case LF_CLASS:
case LF_STRUCTURE:
lldbassert(uid.tag() == PDB_SymType::UDT);
llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, m_cvr.cr));
break;
default:
llvm_unreachable("unreachable!");
}
}
lldb::opaque_compiler_type_t UdtRecordCompleter::AddBaseClassForTypeIndex(
llvm::codeview::TypeIndex ti, llvm::codeview::MemberAccess access) {
TypeSP base_type = m_symbol_file.GetOrCreateType(ti);
CompilerType base_ct = base_type->GetFullCompilerType();
CVType udt_cvt = m_symbol_file.m_index->tpi().getType(ti);
lldb::opaque_compiler_type_t base_qt = base_ct.GetOpaqueQualType();
clang::CXXBaseSpecifier *base_spec =
m_symbol_file.GetASTContext().CreateBaseClassSpecifier(
base_qt, TranslateMemberAccess(access), false,
udt_cvt.kind() == LF_CLASS);
m_bases.push_back(base_spec);
return base_qt;
}
Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
BaseClassRecord &base) {
lldb::opaque_compiler_type_t base_qt =
AddBaseClassForTypeIndex(base.Type, base.getAccess());
auto decl = m_symbol_file.GetASTContext().GetAsCXXRecordDecl(base_qt);
lldbassert(decl);
auto offset = clang::CharUnits::fromQuantity(base.getBaseOffset());
m_layout.base_offsets.insert(std::make_pair(decl, offset));
return llvm::Error::success();
}
Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
VirtualBaseClassRecord &base) {
AddBaseClassForTypeIndex(base.BaseType, base.getAccess());
// FIXME: Handle virtual base offsets.
return Error::success();
}
Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
ListContinuationRecord &cont) {
return Error::success();
}
Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
VFPtrRecord &vfptr) {
return Error::success();
}
Error UdtRecordCompleter::visitKnownMember(
CVMemberRecord &cvr, StaticDataMemberRecord &static_data_member) {
TypeSP member_type = m_symbol_file.GetOrCreateType(static_data_member.Type);
CompilerType complete_member_type = member_type->GetFullCompilerType();
lldb::AccessType access =
TranslateMemberAccess(static_data_member.getAccess());
ClangASTContext::AddVariableToRecordType(
m_derived_ct, static_data_member.Name, complete_member_type, access);
// FIXME: Add a PdbSymUid namespace for field list members and update
// the m_uid_to_decl map with this decl.
return Error::success();
}
Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
NestedTypeRecord &nested) {
return Error::success();
}
Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
DataMemberRecord &data_member) {
TypeSP member_type = m_symbol_file.GetOrCreateType(data_member.Type);
CompilerType complete_member_type = member_type->GetFullCompilerType();
lldb::AccessType access = TranslateMemberAccess(data_member.getAccess());
clang::FieldDecl *decl = ClangASTContext::AddFieldToRecordType(
m_derived_ct, data_member.Name, complete_member_type, access, 0);
// FIXME: Add a PdbSymUid namespace for field list members and update
// the m_uid_to_decl map with this decl.
uint64_t offset = data_member.FieldOffset * 8;
m_layout.field_offsets.insert(std::make_pair(decl, offset));
return Error::success();
}
Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
OneMethodRecord &one_method) {
return Error::success();
}
Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
OverloadedMethodRecord &overloaded) {
return Error::success();
}
Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
EnumeratorRecord &enumerator) {
ClangASTContext &clang = m_symbol_file.GetASTContext();
Declaration decl;
llvm::StringRef name = DropNameScope(enumerator.getName());
lldbassert(m_uid.tag() == PDB_SymType::Enum);
TypeSP underlying_type =
m_symbol_file.GetOrCreateType(m_cvr.er.getUnderlyingType());
lldb::opaque_compiler_type_t enum_qt = m_derived_ct.GetOpaqueQualType();
CompilerType enumerator_type = clang.GetEnumerationIntegerType(enum_qt);
uint64_t byte_size = underlying_type->GetByteSize();
clang.AddEnumerationValueToEnumerationType(
m_derived_ct.GetOpaqueQualType(), enumerator_type, decl,
name.str().c_str(), enumerator.Value.getSExtValue(),
byte_size * 8);
return Error::success();
}
void UdtRecordCompleter::complete() {
ClangASTContext &clang = m_symbol_file.GetASTContext();
clang.SetBaseClassesForClassType(m_derived_ct.GetOpaqueQualType(),
m_bases.data(), m_bases.size());
ClangASTContext::DeleteBaseClassSpecifiers(m_bases.data(), m_bases.size());
clang.AddMethodOverridesForCXXRecordType(m_derived_ct.GetOpaqueQualType());
ClangASTContext::BuildIndirectFields(m_derived_ct);
ClangASTContext::CompleteTagDeclarationDefinition(m_derived_ct);
if (auto *record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(&m_tag_decl)) {
m_symbol_file.GetASTImporter().InsertRecordDecl(record_decl, m_layout);
}
}