1 #include "UdtRecordCompleter.h"
2 
3 #include "PdbIndex.h"
4 #include "PdbSymUid.h"
5 #include "PdbUtil.h"
6 #include "SymbolFileNativePDB.h"
7 
8 #include "lldb/Symbol/ClangASTContext.h"
9 #include "lldb/Symbol/Type.h"
10 #include "lldb/Utility/LLDBAssert.h"
11 #include "lldb/lldb-enumerations.h"
12 #include "lldb/lldb-forward.h"
13 
14 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
15 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
16 #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
17 #include "llvm/DebugInfo/PDB/PDBTypes.h"
18 
19 using namespace llvm::codeview;
20 using namespace llvm::pdb;
21 using namespace lldb;
22 using namespace lldb_private;
23 using namespace lldb_private::npdb;
24 
25 using Error = llvm::Error;
26 
27 UdtRecordCompleter::UdtRecordCompleter(PdbSymUid uid, CompilerType &derived_ct,
28                                        clang::TagDecl &tag_decl,
29                                        SymbolFileNativePDB &symbol_file)
30     : m_uid(uid), m_derived_ct(derived_ct), m_tag_decl(tag_decl),
31       m_symbol_file(symbol_file) {
32   TpiStream &tpi = symbol_file.m_index->tpi();
33   TypeIndex ti(uid.asTypeSym().index);
34   CVType cvt = tpi.getType(ti);
35   switch (cvt.kind()) {
36   case LF_ENUM:
37     lldbassert(uid.tag() == PDB_SymType::Enum);
38     llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, m_cvr.er));
39     break;
40   case LF_UNION:
41     lldbassert(uid.tag() == PDB_SymType::UDT);
42     llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, m_cvr.ur));
43     break;
44   case LF_CLASS:
45   case LF_STRUCTURE:
46     lldbassert(uid.tag() == PDB_SymType::UDT);
47     llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, m_cvr.cr));
48     break;
49   default:
50     llvm_unreachable("unreachable!");
51   }
52 }
53 
54 lldb::opaque_compiler_type_t UdtRecordCompleter::AddBaseClassForTypeIndex(
55     llvm::codeview::TypeIndex ti, llvm::codeview::MemberAccess access) {
56   TypeSP base_type = m_symbol_file.GetOrCreateType(ti);
57   CompilerType base_ct = base_type->GetFullCompilerType();
58 
59   CVType udt_cvt = m_symbol_file.m_index->tpi().getType(ti);
60 
61   lldb::opaque_compiler_type_t base_qt = base_ct.GetOpaqueQualType();
62   std::unique_ptr<clang::CXXBaseSpecifier> base_spec =
63       m_symbol_file.GetASTContext().CreateBaseClassSpecifier(
64           base_qt, TranslateMemberAccess(access), false,
65           udt_cvt.kind() == LF_CLASS);
66   lldbassert(base_spec);
67   m_bases.push_back(std::move(base_spec));
68   return base_qt;
69 }
70 
71 Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
72                                            BaseClassRecord &base) {
73   lldb::opaque_compiler_type_t base_qt =
74       AddBaseClassForTypeIndex(base.Type, base.getAccess());
75 
76   auto decl = m_symbol_file.GetASTContext().GetAsCXXRecordDecl(base_qt);
77   lldbassert(decl);
78 
79   auto offset = clang::CharUnits::fromQuantity(base.getBaseOffset());
80   m_layout.base_offsets.insert(std::make_pair(decl, offset));
81 
82   return llvm::Error::success();
83 }
84 
85 Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
86                                            VirtualBaseClassRecord &base) {
87   AddBaseClassForTypeIndex(base.BaseType, base.getAccess());
88 
89   // FIXME: Handle virtual base offsets.
90   return Error::success();
91 }
92 
93 Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
94                                            ListContinuationRecord &cont) {
95   return Error::success();
96 }
97 
98 Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
99                                            VFPtrRecord &vfptr) {
100   return Error::success();
101 }
102 
103 Error UdtRecordCompleter::visitKnownMember(
104     CVMemberRecord &cvr, StaticDataMemberRecord &static_data_member) {
105   TypeSP member_type = m_symbol_file.GetOrCreateType(static_data_member.Type);
106   CompilerType complete_member_type = member_type->GetFullCompilerType();
107 
108   lldb::AccessType access =
109       TranslateMemberAccess(static_data_member.getAccess());
110   ClangASTContext::AddVariableToRecordType(
111       m_derived_ct, static_data_member.Name, complete_member_type, access);
112 
113   // FIXME: Add a PdbSymUid namespace for field list members and update
114   // the m_uid_to_decl map with this decl.
115   return Error::success();
116 }
117 
118 Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
119                                            NestedTypeRecord &nested) {
120   return Error::success();
121 }
122 
123 Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
124                                            DataMemberRecord &data_member) {
125 
126   TypeSP member_type = m_symbol_file.GetOrCreateType(data_member.Type);
127   CompilerType complete_member_type = member_type->GetFullCompilerType();
128 
129   lldb::AccessType access = TranslateMemberAccess(data_member.getAccess());
130 
131   clang::FieldDecl *decl = ClangASTContext::AddFieldToRecordType(
132       m_derived_ct, data_member.Name, complete_member_type, access, 0);
133   // FIXME: Add a PdbSymUid namespace for field list members and update
134   // the m_uid_to_decl map with this decl.
135 
136   uint64_t offset = data_member.FieldOffset * 8;
137   m_layout.field_offsets.insert(std::make_pair(decl, offset));
138 
139   return Error::success();
140 }
141 
142 Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
143                                            OneMethodRecord &one_method) {
144   return Error::success();
145 }
146 
147 Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
148                                            OverloadedMethodRecord &overloaded) {
149   return Error::success();
150 }
151 
152 Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
153                                            EnumeratorRecord &enumerator) {
154   ClangASTContext &clang = m_symbol_file.GetASTContext();
155 
156   Declaration decl;
157   llvm::StringRef name = DropNameScope(enumerator.getName());
158   lldbassert(m_uid.tag() == PDB_SymType::Enum);
159   TypeSP underlying_type =
160       m_symbol_file.GetOrCreateType(m_cvr.er.getUnderlyingType());
161 
162   lldb::opaque_compiler_type_t enum_qt = m_derived_ct.GetOpaqueQualType();
163 
164   CompilerType enumerator_type = clang.GetEnumerationIntegerType(enum_qt);
165   uint64_t byte_size = underlying_type->GetByteSize();
166   clang.AddEnumerationValueToEnumerationType(
167       m_derived_ct.GetOpaqueQualType(), enumerator_type, decl,
168       name.str().c_str(), enumerator.Value.getSExtValue(),
169       byte_size * 8);
170   return Error::success();
171 }
172 
173 void UdtRecordCompleter::complete() {
174   ClangASTContext &clang = m_symbol_file.GetASTContext();
175   clang.TransferBaseClasses(m_derived_ct.GetOpaqueQualType(),
176                             std::move(m_bases));
177 
178   clang.AddMethodOverridesForCXXRecordType(m_derived_ct.GetOpaqueQualType());
179   ClangASTContext::BuildIndirectFields(m_derived_ct);
180   ClangASTContext::CompleteTagDeclarationDefinition(m_derived_ct);
181 
182   if (auto *record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(&m_tag_decl)) {
183     m_symbol_file.GetASTImporter().InsertRecordDecl(record_decl, m_layout);
184   }
185 }