1 #include "UdtRecordCompleter.h"
2
3 #include "PdbAstBuilder.h"
4 #include "PdbIndex.h"
5 #include "PdbSymUid.h"
6 #include "PdbUtil.h"
7
8 #include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
9 #include "Plugins/ExpressionParser/Clang/ClangUtil.h"
10 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
11 #include "lldb/Symbol/Type.h"
12 #include "lldb/Utility/LLDBAssert.h"
13 #include "lldb/Utility/LLDBLog.h"
14 #include "lldb/lldb-enumerations.h"
15 #include "lldb/lldb-forward.h"
16
17 #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
18 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
19 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
20 #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
21 #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
22 #include "llvm/DebugInfo/PDB/PDBTypes.h"
23
24 using namespace llvm::codeview;
25 using namespace llvm::pdb;
26 using namespace lldb;
27 using namespace lldb_private;
28 using namespace lldb_private::npdb;
29
30 using Error = llvm::Error;
31
UdtRecordCompleter(PdbTypeSymId id,CompilerType & derived_ct,clang::TagDecl & tag_decl,PdbAstBuilder & ast_builder,PdbIndex & index,llvm::DenseMap<lldb::opaque_compiler_type_t,llvm::SmallSet<std::pair<llvm::StringRef,CompilerType>,8>> & cxx_record_map)32 UdtRecordCompleter::UdtRecordCompleter(
33 PdbTypeSymId id, CompilerType &derived_ct, clang::TagDecl &tag_decl,
34 PdbAstBuilder &ast_builder, PdbIndex &index,
35 llvm::DenseMap<lldb::opaque_compiler_type_t,
36 llvm::SmallSet<std::pair<llvm::StringRef, CompilerType>, 8>>
37 &cxx_record_map)
38 : m_id(id), m_derived_ct(derived_ct), m_tag_decl(tag_decl),
39 m_ast_builder(ast_builder), m_index(index),
40 m_cxx_record_map(cxx_record_map) {
41 CVType cvt = m_index.tpi().getType(m_id.index);
42 switch (cvt.kind()) {
43 case LF_ENUM:
44 llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, m_cvr.er));
45 break;
46 case LF_UNION:
47 llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, m_cvr.ur));
48 break;
49 case LF_CLASS:
50 case LF_STRUCTURE:
51 llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, m_cvr.cr));
52 break;
53 default:
54 llvm_unreachable("unreachable!");
55 }
56 }
57
AddBaseClassForTypeIndex(llvm::codeview::TypeIndex ti,llvm::codeview::MemberAccess access,llvm::Optional<uint64_t> vtable_idx)58 clang::QualType UdtRecordCompleter::AddBaseClassForTypeIndex(
59 llvm::codeview::TypeIndex ti, llvm::codeview::MemberAccess access,
60 llvm::Optional<uint64_t> vtable_idx) {
61 PdbTypeSymId type_id(ti);
62 clang::QualType qt = m_ast_builder.GetOrCreateType(type_id);
63
64 CVType udt_cvt = m_index.tpi().getType(ti);
65
66 std::unique_ptr<clang::CXXBaseSpecifier> base_spec =
67 m_ast_builder.clang().CreateBaseClassSpecifier(
68 qt.getAsOpaquePtr(), TranslateMemberAccess(access),
69 vtable_idx.has_value(), udt_cvt.kind() == LF_CLASS);
70 if (!base_spec)
71 return {};
72
73 m_bases.push_back(
74 std::make_pair(vtable_idx.value_or(0), std::move(base_spec)));
75
76 return qt;
77 }
78
AddMethod(llvm::StringRef name,TypeIndex type_idx,MemberAccess access,MethodOptions options,MemberAttributes attrs)79 void UdtRecordCompleter::AddMethod(llvm::StringRef name, TypeIndex type_idx,
80 MemberAccess access, MethodOptions options,
81 MemberAttributes attrs) {
82 clang::QualType method_qt =
83 m_ast_builder.GetOrCreateType(PdbTypeSymId(type_idx));
84 if (method_qt.isNull())
85 return;
86 m_ast_builder.CompleteType(method_qt);
87 CompilerType method_ct = m_ast_builder.ToCompilerType(method_qt);
88 lldb::opaque_compiler_type_t derived_opaque_ty = m_derived_ct.GetOpaqueQualType();
89 auto iter = m_cxx_record_map.find(derived_opaque_ty);
90 if (iter != m_cxx_record_map.end()) {
91 if (iter->getSecond().contains({name, method_ct})) {
92 return;
93 }
94 }
95
96 lldb::AccessType access_type = TranslateMemberAccess(access);
97 bool is_artificial = (options & MethodOptions::CompilerGenerated) ==
98 MethodOptions::CompilerGenerated;
99 m_ast_builder.clang().AddMethodToCXXRecordType(
100 derived_opaque_ty, name.data(), nullptr, method_ct,
101 access_type, attrs.isVirtual(), attrs.isStatic(), false, false, false,
102 is_artificial);
103
104 m_cxx_record_map[derived_opaque_ty].insert({name, method_ct});
105 }
106
visitKnownMember(CVMemberRecord & cvr,BaseClassRecord & base)107 Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
108 BaseClassRecord &base) {
109 clang::QualType base_qt =
110 AddBaseClassForTypeIndex(base.Type, base.getAccess());
111
112 if (base_qt.isNull())
113 return llvm::Error::success();
114 auto decl =
115 m_ast_builder.clang().GetAsCXXRecordDecl(base_qt.getAsOpaquePtr());
116 lldbassert(decl);
117
118 auto offset = clang::CharUnits::fromQuantity(base.getBaseOffset());
119 m_layout.base_offsets.insert(std::make_pair(decl, offset));
120
121 return llvm::Error::success();
122 }
123
visitKnownMember(CVMemberRecord & cvr,VirtualBaseClassRecord & base)124 Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
125 VirtualBaseClassRecord &base) {
126 AddBaseClassForTypeIndex(base.BaseType, base.getAccess(), base.VTableIndex);
127
128 return Error::success();
129 }
130
visitKnownMember(CVMemberRecord & cvr,ListContinuationRecord & cont)131 Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
132 ListContinuationRecord &cont) {
133 return Error::success();
134 }
135
visitKnownMember(CVMemberRecord & cvr,VFPtrRecord & vfptr)136 Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
137 VFPtrRecord &vfptr) {
138 return Error::success();
139 }
140
visitKnownMember(CVMemberRecord & cvr,StaticDataMemberRecord & static_data_member)141 Error UdtRecordCompleter::visitKnownMember(
142 CVMemberRecord &cvr, StaticDataMemberRecord &static_data_member) {
143 clang::QualType member_type =
144 m_ast_builder.GetOrCreateType(PdbTypeSymId(static_data_member.Type));
145 if (member_type.isNull())
146 return llvm::Error::success();
147
148 CompilerType member_ct = m_ast_builder.ToCompilerType(member_type);
149
150 lldb::AccessType access =
151 TranslateMemberAccess(static_data_member.getAccess());
152 auto decl = TypeSystemClang::AddVariableToRecordType(
153 m_derived_ct, static_data_member.Name, member_ct, access);
154
155 // Static constant members may be a const[expr] declaration.
156 // Query the symbol's value as the variable initializer if valid.
157 if (member_ct.IsConst() && member_ct.IsCompleteType()) {
158 std::string qual_name = decl->getQualifiedNameAsString();
159
160 auto results =
161 m_index.globals().findRecordsByName(qual_name, m_index.symrecords());
162
163 for (const auto &result : results) {
164 if (result.second.kind() == SymbolKind::S_CONSTANT) {
165 ConstantSym constant(SymbolRecordKind::ConstantSym);
166 cantFail(SymbolDeserializer::deserializeAs<ConstantSym>(result.second,
167 constant));
168
169 clang::QualType qual_type = decl->getType();
170 unsigned type_width = decl->getASTContext().getIntWidth(qual_type);
171 unsigned constant_width = constant.Value.getBitWidth();
172
173 if (qual_type->isIntegralOrEnumerationType()) {
174 if (type_width >= constant_width) {
175 TypeSystemClang::SetIntegerInitializerForVariable(
176 decl, constant.Value.extOrTrunc(type_width));
177 } else {
178 LLDB_LOG(GetLog(LLDBLog::AST),
179 "Class '{0}' has a member '{1}' of type '{2}' ({3} bits) "
180 "which resolves to a wider constant value ({4} bits). "
181 "Ignoring constant.",
182 m_derived_ct.GetTypeName(), static_data_member.Name,
183 member_ct.GetTypeName(), type_width, constant_width);
184 }
185 } else {
186 lldb::BasicType basic_type_enum = member_ct.GetBasicTypeEnumeration();
187 switch (basic_type_enum) {
188 case lldb::eBasicTypeFloat:
189 case lldb::eBasicTypeDouble:
190 case lldb::eBasicTypeLongDouble:
191 if (type_width == constant_width) {
192 TypeSystemClang::SetFloatingInitializerForVariable(
193 decl, basic_type_enum == lldb::eBasicTypeFloat
194 ? llvm::APFloat(constant.Value.bitsToFloat())
195 : llvm::APFloat(constant.Value.bitsToDouble()));
196 decl->setConstexpr(true);
197 } else {
198 LLDB_LOG(
199 GetLog(LLDBLog::AST),
200 "Class '{0}' has a member '{1}' of type '{2}' ({3} bits) "
201 "which resolves to a constant value of mismatched width "
202 "({4} bits). Ignoring constant.",
203 m_derived_ct.GetTypeName(), static_data_member.Name,
204 member_ct.GetTypeName(), type_width, constant_width);
205 }
206 break;
207 default:
208 break;
209 }
210 }
211 break;
212 }
213 }
214 }
215
216 // FIXME: Add a PdbSymUid namespace for field list members and update
217 // the m_uid_to_decl map with this decl.
218 return Error::success();
219 }
220
visitKnownMember(CVMemberRecord & cvr,NestedTypeRecord & nested)221 Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
222 NestedTypeRecord &nested) {
223 return Error::success();
224 }
225
visitKnownMember(CVMemberRecord & cvr,DataMemberRecord & data_member)226 Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
227 DataMemberRecord &data_member) {
228
229 uint64_t offset = data_member.FieldOffset * 8;
230 uint32_t bitfield_width = 0;
231
232 TypeIndex ti(data_member.Type);
233 if (!ti.isSimple()) {
234 CVType cvt = m_index.tpi().getType(ti);
235 if (cvt.kind() == LF_BITFIELD) {
236 BitFieldRecord bfr;
237 llvm::cantFail(TypeDeserializer::deserializeAs<BitFieldRecord>(cvt, bfr));
238 offset += bfr.BitOffset;
239 bitfield_width = bfr.BitSize;
240 ti = bfr.Type;
241 }
242 }
243
244 clang::QualType member_qt = m_ast_builder.GetOrCreateType(PdbTypeSymId(ti));
245 if (member_qt.isNull())
246 return Error::success();
247 m_ast_builder.CompleteType(member_qt);
248
249 lldb::AccessType access = TranslateMemberAccess(data_member.getAccess());
250
251 clang::FieldDecl *decl = TypeSystemClang::AddFieldToRecordType(
252 m_derived_ct, data_member.Name, m_ast_builder.ToCompilerType(member_qt),
253 access, bitfield_width);
254 // FIXME: Add a PdbSymUid namespace for field list members and update
255 // the m_uid_to_decl map with this decl.
256
257 m_layout.field_offsets.insert(std::make_pair(decl, offset));
258
259 return Error::success();
260 }
261
visitKnownMember(CVMemberRecord & cvr,OneMethodRecord & one_method)262 Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
263 OneMethodRecord &one_method) {
264 AddMethod(one_method.Name, one_method.Type, one_method.getAccess(),
265 one_method.getOptions(), one_method.Attrs);
266
267 return Error::success();
268 }
269
visitKnownMember(CVMemberRecord & cvr,OverloadedMethodRecord & overloaded)270 Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
271 OverloadedMethodRecord &overloaded) {
272 TypeIndex method_list_idx = overloaded.MethodList;
273
274 CVType method_list_type = m_index.tpi().getType(method_list_idx);
275 assert(method_list_type.kind() == LF_METHODLIST);
276
277 MethodOverloadListRecord method_list;
278 llvm::cantFail(TypeDeserializer::deserializeAs<MethodOverloadListRecord>(
279 method_list_type, method_list));
280
281 for (const OneMethodRecord &method : method_list.Methods)
282 AddMethod(overloaded.Name, method.Type, method.getAccess(),
283 method.getOptions(), method.Attrs);
284
285 return Error::success();
286 }
287
visitKnownMember(CVMemberRecord & cvr,EnumeratorRecord & enumerator)288 Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
289 EnumeratorRecord &enumerator) {
290 Declaration decl;
291 llvm::StringRef name = DropNameScope(enumerator.getName());
292
293 m_ast_builder.clang().AddEnumerationValueToEnumerationType(
294 m_derived_ct, decl, name.str().c_str(), enumerator.Value);
295 return Error::success();
296 }
297
complete()298 void UdtRecordCompleter::complete() {
299 // Ensure the correct order for virtual bases.
300 llvm::stable_sort(m_bases, llvm::less_first());
301
302 std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> bases;
303 bases.reserve(m_bases.size());
304 for (auto &ib : m_bases)
305 bases.push_back(std::move(ib.second));
306
307 TypeSystemClang &clang = m_ast_builder.clang();
308 clang.TransferBaseClasses(m_derived_ct.GetOpaqueQualType(), std::move(bases));
309
310 clang.AddMethodOverridesForCXXRecordType(m_derived_ct.GetOpaqueQualType());
311 TypeSystemClang::BuildIndirectFields(m_derived_ct);
312 TypeSystemClang::CompleteTagDeclarationDefinition(m_derived_ct);
313
314 if (auto *record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(&m_tag_decl)) {
315 m_ast_builder.importer().SetRecordLayout(record_decl, m_layout);
316 }
317 }
318