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