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   uint64_t offset = data_member.FieldOffset * 8;
127   uint32_t bitfield_width = 0;
128 
129   TypeSP member_type;
130   TpiStream &tpi = m_symbol_file.m_index->tpi();
131   TypeIndex ti(data_member.Type);
132   if (!ti.isSimple()) {
133     CVType cvt = tpi.getType(ti);
134     if (cvt.kind() == LF_BITFIELD) {
135       BitFieldRecord bfr;
136       llvm::cantFail(TypeDeserializer::deserializeAs<BitFieldRecord>(cvt, bfr));
137       offset += bfr.BitOffset;
138       bitfield_width = bfr.BitSize;
139       ti = bfr.Type;
140     }
141   }
142 
143   member_type = m_symbol_file.GetOrCreateType(ti);
144   CompilerType complete_member_type = member_type->GetFullCompilerType();
145   lldb::AccessType access = TranslateMemberAccess(data_member.getAccess());
146 
147   clang::FieldDecl *decl = ClangASTContext::AddFieldToRecordType(
148       m_derived_ct, data_member.Name, complete_member_type, access,
149       bitfield_width);
150   // FIXME: Add a PdbSymUid namespace for field list members and update
151   // the m_uid_to_decl map with this decl.
152 
153   m_layout.field_offsets.insert(std::make_pair(decl, offset));
154 
155   return Error::success();
156 }
157 
158 Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
159                                            OneMethodRecord &one_method) {
160   return Error::success();
161 }
162 
163 Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
164                                            OverloadedMethodRecord &overloaded) {
165   return Error::success();
166 }
167 
168 Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
169                                            EnumeratorRecord &enumerator) {
170   ClangASTContext &clang = m_symbol_file.GetASTContext();
171 
172   Declaration decl;
173   llvm::StringRef name = DropNameScope(enumerator.getName());
174   lldbassert(m_uid.tag() == PDB_SymType::Enum);
175   TypeSP underlying_type =
176       m_symbol_file.GetOrCreateType(m_cvr.er.getUnderlyingType());
177 
178   uint64_t byte_size = underlying_type->GetByteSize();
179   clang.AddEnumerationValueToEnumerationType(
180       m_derived_ct, decl, name.str().c_str(), enumerator.Value.getSExtValue(),
181       byte_size * 8);
182   return Error::success();
183 }
184 
185 void UdtRecordCompleter::complete() {
186   ClangASTContext &clang = m_symbol_file.GetASTContext();
187   clang.TransferBaseClasses(m_derived_ct.GetOpaqueQualType(),
188                             std::move(m_bases));
189 
190   clang.AddMethodOverridesForCXXRecordType(m_derived_ct.GetOpaqueQualType());
191   ClangASTContext::BuildIndirectFields(m_derived_ct);
192   ClangASTContext::CompleteTagDeclarationDefinition(m_derived_ct);
193 
194   if (auto *record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(&m_tag_decl)) {
195     m_symbol_file.GetASTImporter().InsertRecordDecl(record_decl, m_layout);
196   }
197 }
198