| 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/ClangASTMetadata.h" |
| 10 | #include "Plugins/ExpressionParser/Clang/ClangUtil.h" |
| 11 | #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" |
| 12 | #include "SymbolFileNativePDB.h" |
| 13 | #include "lldb/Core/Address.h" |
| 14 | #include "lldb/Symbol/Type.h" |
| 15 | #include "lldb/Utility/LLDBAssert.h" |
| 16 | #include "lldb/Utility/LLDBLog.h" |
| 17 | #include "lldb/lldb-enumerations.h" |
| 18 | #include "lldb/lldb-forward.h" |
| 19 | |
| 20 | #include "llvm/ADT/STLExtras.h" |
| 21 | #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" |
| 22 | #include "llvm/DebugInfo/CodeView/TypeDeserializer.h" |
| 23 | #include "llvm/DebugInfo/CodeView/TypeIndex.h" |
| 24 | #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" |
| 25 | #include "llvm/DebugInfo/PDB/Native/TpiStream.h" |
| 26 | #include "llvm/DebugInfo/PDB/PDBTypes.h" |
| 27 | #include <optional> |
| 28 | |
| 29 | using namespace llvm::codeview; |
| 30 | using namespace llvm::pdb; |
| 31 | using namespace lldb; |
| 32 | using namespace lldb_private; |
| 33 | using namespace lldb_private::npdb; |
| 34 | |
| 35 | using Error = llvm::Error; |
| 36 | |
| 37 | UdtRecordCompleter::UdtRecordCompleter( |
| 38 | PdbTypeSymId id, CompilerType &derived_ct, clang::TagDecl &tag_decl, |
| 39 | PdbAstBuilder &ast_builder, PdbIndex &index, |
| 40 | llvm::DenseMap<clang::Decl *, DeclStatus> &decl_to_status, |
| 41 | llvm::DenseMap<lldb::opaque_compiler_type_t, |
| 42 | llvm::SmallSet<std::pair<llvm::StringRef, CompilerType>, 8>> |
| 43 | &cxx_record_map) |
| 44 | : m_id(id), m_derived_ct(derived_ct), m_tag_decl(tag_decl), |
| 45 | m_ast_builder(ast_builder), m_index(index), |
| 46 | m_decl_to_status(decl_to_status), m_cxx_record_map(cxx_record_map) { |
| 47 | CVType cvt = m_index.tpi().getType(Index: m_id.index); |
| 48 | switch (cvt.kind()) { |
| 49 | case LF_ENUM: |
| 50 | m_cvr.er.Options = ClassOptions::None; |
| 51 | llvm::cantFail(Err: TypeDeserializer::deserializeAs<EnumRecord>(CVT&: cvt, Record&: m_cvr.er)); |
| 52 | break; |
| 53 | case LF_UNION: |
| 54 | m_cvr.ur.Options = ClassOptions::None; |
| 55 | llvm::cantFail(Err: TypeDeserializer::deserializeAs<UnionRecord>(CVT&: cvt, Record&: m_cvr.ur)); |
| 56 | m_layout.bit_size = m_cvr.ur.getSize() * 8; |
| 57 | m_record.record.kind = Member::Union; |
| 58 | break; |
| 59 | case LF_CLASS: |
| 60 | case LF_STRUCTURE: |
| 61 | m_cvr.cr.Options = ClassOptions::None; |
| 62 | llvm::cantFail(Err: TypeDeserializer::deserializeAs<ClassRecord>(CVT&: cvt, Record&: m_cvr.cr)); |
| 63 | m_layout.bit_size = m_cvr.cr.getSize() * 8; |
| 64 | m_record.record.kind = Member::Struct; |
| 65 | break; |
| 66 | default: |
| 67 | llvm_unreachable("unreachable!" ); |
| 68 | } |
| 69 | } |
| 70 | |
| 71 | clang::QualType UdtRecordCompleter::AddBaseClassForTypeIndex( |
| 72 | llvm::codeview::TypeIndex ti, llvm::codeview::MemberAccess access, |
| 73 | std::optional<uint64_t> vtable_idx) { |
| 74 | PdbTypeSymId type_id(ti); |
| 75 | clang::QualType qt = m_ast_builder.GetOrCreateType(type: type_id); |
| 76 | |
| 77 | CVType udt_cvt = m_index.tpi().getType(Index: ti); |
| 78 | |
| 79 | std::unique_ptr<clang::CXXBaseSpecifier> base_spec = |
| 80 | m_ast_builder.clang().CreateBaseClassSpecifier( |
| 81 | type: qt.getAsOpaquePtr(), access: TranslateMemberAccess(access), |
| 82 | is_virtual: vtable_idx.has_value(), base_of_class: udt_cvt.kind() == LF_CLASS); |
| 83 | if (!base_spec) |
| 84 | return {}; |
| 85 | |
| 86 | m_bases.push_back( |
| 87 | x: std::make_pair(x: vtable_idx.value_or(u: 0), y: std::move(base_spec))); |
| 88 | |
| 89 | return qt; |
| 90 | } |
| 91 | |
| 92 | void UdtRecordCompleter::AddMethod(llvm::StringRef name, TypeIndex type_idx, |
| 93 | MemberAccess access, MethodOptions options, |
| 94 | MemberAttributes attrs) { |
| 95 | clang::QualType method_qt = |
| 96 | m_ast_builder.GetOrCreateType(type: PdbTypeSymId(type_idx)); |
| 97 | if (method_qt.isNull()) |
| 98 | return; |
| 99 | CompilerType method_ct = m_ast_builder.ToCompilerType(qt: method_qt); |
| 100 | TypeSystemClang::RequireCompleteType(type: method_ct); |
| 101 | lldb::opaque_compiler_type_t derived_opaque_ty = |
| 102 | m_derived_ct.GetOpaqueQualType(); |
| 103 | auto iter = m_cxx_record_map.find(Val: derived_opaque_ty); |
| 104 | if (iter != m_cxx_record_map.end()) { |
| 105 | if (iter->getSecond().contains(V: {name, method_ct})) { |
| 106 | return; |
| 107 | } |
| 108 | } |
| 109 | |
| 110 | lldb::AccessType access_type = TranslateMemberAccess(access); |
| 111 | bool is_artificial = (options & MethodOptions::CompilerGenerated) == |
| 112 | MethodOptions::CompilerGenerated; |
| 113 | m_ast_builder.clang().AddMethodToCXXRecordType( |
| 114 | type: derived_opaque_ty, name: name.data(), mangled_name: nullptr, method_type: method_ct, |
| 115 | access: access_type, is_virtual: attrs.isVirtual(), is_static: attrs.isStatic(), is_inline: false, is_explicit: false, is_attr_used: false, |
| 116 | is_artificial); |
| 117 | |
| 118 | m_cxx_record_map[derived_opaque_ty].insert(V: {name, method_ct}); |
| 119 | } |
| 120 | |
| 121 | Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, |
| 122 | BaseClassRecord &base) { |
| 123 | clang::QualType base_qt = |
| 124 | AddBaseClassForTypeIndex(ti: base.Type, access: base.getAccess()); |
| 125 | |
| 126 | if (base_qt.isNull()) |
| 127 | return llvm::Error::success(); |
| 128 | auto decl = |
| 129 | m_ast_builder.clang().GetAsCXXRecordDecl(type: base_qt.getAsOpaquePtr()); |
| 130 | lldbassert(decl); |
| 131 | |
| 132 | auto offset = clang::CharUnits::fromQuantity(Quantity: base.getBaseOffset()); |
| 133 | m_layout.base_offsets.insert(KV: std::make_pair(x&: decl, y&: offset)); |
| 134 | |
| 135 | return llvm::Error::success(); |
| 136 | } |
| 137 | |
| 138 | Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, |
| 139 | VirtualBaseClassRecord &base) { |
| 140 | AddBaseClassForTypeIndex(ti: base.BaseType, access: base.getAccess(), vtable_idx: base.VTableIndex); |
| 141 | |
| 142 | return Error::success(); |
| 143 | } |
| 144 | |
| 145 | Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, |
| 146 | ListContinuationRecord &cont) { |
| 147 | return Error::success(); |
| 148 | } |
| 149 | |
| 150 | Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, |
| 151 | VFPtrRecord &vfptr) { |
| 152 | return Error::success(); |
| 153 | } |
| 154 | |
| 155 | Error UdtRecordCompleter::visitKnownMember( |
| 156 | CVMemberRecord &cvr, StaticDataMemberRecord &static_data_member) { |
| 157 | clang::QualType member_type = |
| 158 | m_ast_builder.GetOrCreateType(type: PdbTypeSymId(static_data_member.Type)); |
| 159 | if (member_type.isNull()) |
| 160 | return llvm::Error::success(); |
| 161 | |
| 162 | CompilerType member_ct = m_ast_builder.ToCompilerType(qt: member_type); |
| 163 | |
| 164 | lldb::AccessType access = |
| 165 | TranslateMemberAccess(access: static_data_member.getAccess()); |
| 166 | auto decl = TypeSystemClang::AddVariableToRecordType( |
| 167 | type: m_derived_ct, name: static_data_member.Name, var_type: member_ct, access); |
| 168 | |
| 169 | // Static constant members may be a const[expr] declaration. |
| 170 | // Query the symbol's value as the variable initializer if valid. |
| 171 | if (member_ct.IsConst() && member_ct.IsCompleteType()) { |
| 172 | std::string qual_name = decl->getQualifiedNameAsString(); |
| 173 | |
| 174 | auto results = |
| 175 | m_index.globals().findRecordsByName(Name: qual_name, Symbols: m_index.symrecords()); |
| 176 | |
| 177 | for (const auto &result : results) { |
| 178 | if (result.second.kind() == SymbolKind::S_CONSTANT) { |
| 179 | ConstantSym constant(SymbolRecordKind::ConstantSym); |
| 180 | cantFail(SymbolDeserializer::deserializeAs<ConstantSym>(result.second, |
| 181 | constant)); |
| 182 | |
| 183 | clang::QualType qual_type = decl->getType(); |
| 184 | unsigned type_width = decl->getASTContext().getIntWidth(qual_type); |
| 185 | unsigned constant_width = constant.Value.getBitWidth(); |
| 186 | |
| 187 | if (qual_type->isIntegralOrEnumerationType()) { |
| 188 | if (type_width >= constant_width) { |
| 189 | TypeSystemClang::SetIntegerInitializerForVariable( |
| 190 | decl, constant.Value.extOrTrunc(type_width)); |
| 191 | } else { |
| 192 | LLDB_LOG(GetLog(LLDBLog::AST), |
| 193 | "Class '{0}' has a member '{1}' of type '{2}' ({3} bits) " |
| 194 | "which resolves to a wider constant value ({4} bits). " |
| 195 | "Ignoring constant." , |
| 196 | m_derived_ct.GetTypeName(), static_data_member.Name, |
| 197 | member_ct.GetTypeName(), type_width, constant_width); |
| 198 | } |
| 199 | } else { |
| 200 | lldb::BasicType basic_type_enum = member_ct.GetBasicTypeEnumeration(); |
| 201 | switch (basic_type_enum) { |
| 202 | case lldb::eBasicTypeFloat: |
| 203 | case lldb::eBasicTypeDouble: |
| 204 | case lldb::eBasicTypeLongDouble: |
| 205 | if (type_width == constant_width) { |
| 206 | TypeSystemClang::SetFloatingInitializerForVariable( |
| 207 | decl, basic_type_enum == lldb::eBasicTypeFloat |
| 208 | ? llvm::APFloat(constant.Value.bitsToFloat()) |
| 209 | : llvm::APFloat(constant.Value.bitsToDouble())); |
| 210 | decl->setConstexpr(true); |
| 211 | } else { |
| 212 | LLDB_LOG( |
| 213 | GetLog(LLDBLog::AST), |
| 214 | "Class '{0}' has a member '{1}' of type '{2}' ({3} bits) " |
| 215 | "which resolves to a constant value of mismatched width " |
| 216 | "({4} bits). Ignoring constant." , |
| 217 | m_derived_ct.GetTypeName(), static_data_member.Name, |
| 218 | member_ct.GetTypeName(), type_width, constant_width); |
| 219 | } |
| 220 | break; |
| 221 | default: |
| 222 | break; |
| 223 | } |
| 224 | } |
| 225 | break; |
| 226 | } |
| 227 | } |
| 228 | } |
| 229 | |
| 230 | // FIXME: Add a PdbSymUid namespace for field list members and update |
| 231 | // the m_uid_to_decl map with this decl. |
| 232 | return Error::success(); |
| 233 | } |
| 234 | |
| 235 | Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, |
| 236 | NestedTypeRecord &nested) { |
| 237 | return Error::success(); |
| 238 | } |
| 239 | |
| 240 | Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, |
| 241 | DataMemberRecord &data_member) { |
| 242 | |
| 243 | uint64_t offset = data_member.FieldOffset * 8; |
| 244 | uint32_t bitfield_width = 0; |
| 245 | |
| 246 | TypeIndex ti(data_member.Type); |
| 247 | if (!ti.isSimple()) { |
| 248 | CVType cvt = m_index.tpi().getType(Index: ti); |
| 249 | if (cvt.kind() == LF_BITFIELD) { |
| 250 | BitFieldRecord bfr; |
| 251 | llvm::cantFail(Err: TypeDeserializer::deserializeAs<BitFieldRecord>(CVT&: cvt, Record&: bfr)); |
| 252 | offset += bfr.BitOffset; |
| 253 | bitfield_width = bfr.BitSize; |
| 254 | ti = bfr.Type; |
| 255 | } |
| 256 | } |
| 257 | |
| 258 | clang::QualType member_qt = m_ast_builder.GetOrCreateType(type: PdbTypeSymId(ti)); |
| 259 | if (member_qt.isNull()) |
| 260 | return Error::success(); |
| 261 | TypeSystemClang::RequireCompleteType(type: m_ast_builder.ToCompilerType(qt: member_qt)); |
| 262 | lldb::AccessType access = TranslateMemberAccess(access: data_member.getAccess()); |
| 263 | size_t field_size = |
| 264 | bitfield_width ? bitfield_width : GetSizeOfType(id: ti, tpi&: m_index.tpi()) * 8; |
| 265 | if (field_size == 0) |
| 266 | return Error::success(); |
| 267 | m_record.CollectMember(data_member.Name, offset, field_size, member_qt, access, |
| 268 | bitfield_width); |
| 269 | return Error::success(); |
| 270 | } |
| 271 | |
| 272 | Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, |
| 273 | OneMethodRecord &one_method) { |
| 274 | AddMethod(name: one_method.Name, type_idx: one_method.Type, access: one_method.getAccess(), |
| 275 | options: one_method.getOptions(), attrs: one_method.Attrs); |
| 276 | |
| 277 | return Error::success(); |
| 278 | } |
| 279 | |
| 280 | Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, |
| 281 | OverloadedMethodRecord &overloaded) { |
| 282 | TypeIndex method_list_idx = overloaded.MethodList; |
| 283 | |
| 284 | CVType method_list_type = m_index.tpi().getType(Index: method_list_idx); |
| 285 | assert(method_list_type.kind() == LF_METHODLIST); |
| 286 | |
| 287 | MethodOverloadListRecord method_list; |
| 288 | llvm::cantFail(Err: TypeDeserializer::deserializeAs<MethodOverloadListRecord>( |
| 289 | CVT&: method_list_type, Record&: method_list)); |
| 290 | |
| 291 | for (const OneMethodRecord &method : method_list.Methods) |
| 292 | AddMethod(name: overloaded.Name, type_idx: method.Type, access: method.getAccess(), |
| 293 | options: method.getOptions(), attrs: method.Attrs); |
| 294 | |
| 295 | return Error::success(); |
| 296 | } |
| 297 | |
| 298 | Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, |
| 299 | EnumeratorRecord &enumerator) { |
| 300 | Declaration decl; |
| 301 | llvm::StringRef name = DropNameScope(name: enumerator.getName()); |
| 302 | |
| 303 | m_ast_builder.clang().AddEnumerationValueToEnumerationType( |
| 304 | enum_type: m_derived_ct, decl, name: name.str().c_str(), value: enumerator.Value); |
| 305 | return Error::success(); |
| 306 | } |
| 307 | |
| 308 | void UdtRecordCompleter::complete() { |
| 309 | // Ensure the correct order for virtual bases. |
| 310 | llvm::stable_sort(Range&: m_bases, C: llvm::less_first()); |
| 311 | |
| 312 | std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> bases; |
| 313 | bases.reserve(n: m_bases.size()); |
| 314 | for (auto &ib : m_bases) |
| 315 | bases.push_back(x: std::move(ib.second)); |
| 316 | |
| 317 | TypeSystemClang &clang = m_ast_builder.clang(); |
| 318 | // Make sure all base classes refer to complete types and not forward |
| 319 | // declarations. If we don't do this, clang will crash with an |
| 320 | // assertion in the call to clang_type.TransferBaseClasses() |
| 321 | for (const auto &base_class : bases) { |
| 322 | clang::TypeSourceInfo *type_source_info = |
| 323 | base_class->getTypeSourceInfo(); |
| 324 | if (type_source_info) { |
| 325 | TypeSystemClang::RequireCompleteType( |
| 326 | type: clang.GetType(qt: type_source_info->getType())); |
| 327 | } |
| 328 | } |
| 329 | |
| 330 | clang.TransferBaseClasses(type: m_derived_ct.GetOpaqueQualType(), bases: std::move(bases)); |
| 331 | |
| 332 | clang.AddMethodOverridesForCXXRecordType(type: m_derived_ct.GetOpaqueQualType()); |
| 333 | FinishRecord(); |
| 334 | TypeSystemClang::BuildIndirectFields(type: m_derived_ct); |
| 335 | TypeSystemClang::CompleteTagDeclarationDefinition(type: m_derived_ct); |
| 336 | |
| 337 | if (auto *record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(Val: &m_tag_decl)) { |
| 338 | m_ast_builder.GetClangASTImporter().SetRecordLayout(record_decl, m_layout); |
| 339 | } |
| 340 | } |
| 341 | |
| 342 | uint64_t |
| 343 | UdtRecordCompleter::AddMember(TypeSystemClang &clang, Member *field, |
| 344 | uint64_t bit_offset, CompilerType parent_ct, |
| 345 | ClangASTImporter::LayoutInfo &parent_layout, |
| 346 | clang::DeclContext *parent_decl_ctx) { |
| 347 | SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>( |
| 348 | clang.GetSymbolFile()->GetBackingSymbolFile()); |
| 349 | clang::FieldDecl *field_decl = nullptr; |
| 350 | uint64_t bit_size = 0; |
| 351 | switch (field->kind) { |
| 352 | case Member::Field: { |
| 353 | field_decl = TypeSystemClang::AddFieldToRecordType( |
| 354 | type: parent_ct, name: field->name, field_type: m_ast_builder.ToCompilerType(qt: field->qt), |
| 355 | access: field->access, bitfield_bit_size: field->bitfield_width); |
| 356 | bit_size = field->bit_size; |
| 357 | break; |
| 358 | }; |
| 359 | case Member::Struct: |
| 360 | case Member::Union: { |
| 361 | clang::TagTypeKind kind = field->kind == Member::Struct |
| 362 | ? clang::TagTypeKind::Struct |
| 363 | : clang::TagTypeKind::Union; |
| 364 | ClangASTMetadata metadata; |
| 365 | metadata.SetUserID(pdb->anonymous_id); |
| 366 | metadata.SetIsDynamicCXXType(false); |
| 367 | CompilerType record_ct = clang.CreateRecordType( |
| 368 | decl_ctx: parent_decl_ctx, owning_module: OptionalClangModuleID(), access_type: lldb::eAccessPublic, name: "" , |
| 369 | kind: llvm::to_underlying(E: kind), language: lldb::eLanguageTypeC_plus_plus, metadata); |
| 370 | TypeSystemClang::StartTagDeclarationDefinition(type: record_ct); |
| 371 | ClangASTImporter::LayoutInfo layout; |
| 372 | clang::DeclContext *decl_ctx = clang.GetDeclContextForType(type: record_ct); |
| 373 | for (const auto &member : field->fields) { |
| 374 | uint64_t member_offset = field->kind == Member::Struct |
| 375 | ? member->bit_offset - field->base_offset |
| 376 | : 0; |
| 377 | uint64_t member_bit_size = AddMember(clang, field: member.get(), bit_offset: member_offset, |
| 378 | parent_ct: record_ct, parent_layout&: layout, parent_decl_ctx: decl_ctx); |
| 379 | if (field->kind == Member::Struct) |
| 380 | bit_size = std::max(a: bit_size, b: member_offset + member_bit_size); |
| 381 | else |
| 382 | bit_size = std::max(a: bit_size, b: member_bit_size); |
| 383 | } |
| 384 | layout.bit_size = bit_size; |
| 385 | TypeSystemClang::CompleteTagDeclarationDefinition(type: record_ct); |
| 386 | clang::RecordDecl *record_decl = clang.GetAsRecordDecl(type: record_ct); |
| 387 | m_ast_builder.GetClangASTImporter().SetRecordLayout(decl: record_decl, layout); |
| 388 | field_decl = TypeSystemClang::AddFieldToRecordType( |
| 389 | type: parent_ct, name: "" , field_type: record_ct, access: lldb::eAccessPublic, bitfield_bit_size: 0); |
| 390 | // Mark this record decl as completed. |
| 391 | DeclStatus status; |
| 392 | status.resolved = true; |
| 393 | status.uid = pdb->anonymous_id--; |
| 394 | m_decl_to_status.insert({record_decl, status}); |
| 395 | break; |
| 396 | }; |
| 397 | } |
| 398 | // FIXME: Add a PdbSymUid namespace for field list members and update |
| 399 | // the m_uid_to_decl map with this decl. |
| 400 | parent_layout.field_offsets.insert(KV: {field_decl, bit_offset}); |
| 401 | return bit_size; |
| 402 | } |
| 403 | |
| 404 | void UdtRecordCompleter::FinishRecord() { |
| 405 | TypeSystemClang &clang = m_ast_builder.clang(); |
| 406 | clang::DeclContext *decl_ctx = |
| 407 | m_ast_builder.GetOrCreateDeclContextForUid(uid: m_id); |
| 408 | m_record.ConstructRecord(); |
| 409 | // Maybe we should check the construsted record size with the size in pdb. If |
| 410 | // they mismatch, it might be pdb has fields info missing. |
| 411 | for (const auto &field : m_record.record.fields) { |
| 412 | AddMember(clang, field.get(), field->bit_offset, m_derived_ct, m_layout, |
| 413 | decl_ctx); |
| 414 | } |
| 415 | } |
| 416 | |
| 417 | void UdtRecordCompleter::Record::CollectMember( |
| 418 | llvm::StringRef name, uint64_t offset, uint64_t field_size, |
| 419 | clang::QualType qt, lldb::AccessType access, uint64_t bitfield_width) { |
| 420 | fields_map[offset].push_back(Elt: std::make_unique<Member>( |
| 421 | args&: name, args&: offset, args&: field_size, args&: qt, args&: access, args&: bitfield_width)); |
| 422 | if (start_offset > offset) |
| 423 | start_offset = offset; |
| 424 | } |
| 425 | |
| 426 | void UdtRecordCompleter::Record::ConstructRecord() { |
| 427 | // For anonymous unions in a struct, msvc generated pdb doesn't have the |
| 428 | // entity for that union. So, we need to construct anonymous union and struct |
| 429 | // based on field offsets. The final AST is likely not matching the exact |
| 430 | // original AST, but the memory layout is preseved. |
| 431 | // After we collecting all fields in visitKnownMember, we have all fields in |
| 432 | // increasing offset order in m_fields. Since we are iterating in increase |
| 433 | // offset order, if the current offset is equal to m_start_offset, we insert |
| 434 | // it as direct field of top level record. If the current offset is greater |
| 435 | // than m_start_offset, we should be able to find a field in end_offset_map |
| 436 | // whose end offset is less than or equal to current offset. (if not, it might |
| 437 | // be missing field info. We will ignore the field in this case. e.g. Field A |
| 438 | // starts at 0 with size 4 bytes, and Field B starts at 2 with size 4 bytes. |
| 439 | // Normally, there must be something which ends at/before 2.) Then we will |
| 440 | // append current field to the end of parent record. If parent is struct, we |
| 441 | // can just grow it. If parent is a field, it's a field inside an union. We |
| 442 | // convert it into an anonymous struct containing old field and new field. |
| 443 | |
| 444 | // The end offset to a vector of field/struct that ends at the offset. |
| 445 | std::map<uint64_t, std::vector<Member *>> end_offset_map; |
| 446 | for (auto &pair : fields_map) { |
| 447 | uint64_t offset = pair.first; |
| 448 | auto &fields = pair.second; |
| 449 | lldbassert(offset >= start_offset); |
| 450 | Member *parent = &record; |
| 451 | if (offset > start_offset) { |
| 452 | // Find the field with largest end offset that is <= offset. If it's less |
| 453 | // than offset, it indicates there are padding bytes between end offset |
| 454 | // and offset. |
| 455 | lldbassert(!end_offset_map.empty()); |
| 456 | auto iter = end_offset_map.lower_bound(x: offset); |
| 457 | if (iter == end_offset_map.end()) |
| 458 | --iter; |
| 459 | else if (iter->first > offset) { |
| 460 | if (iter == end_offset_map.begin()) |
| 461 | continue; |
| 462 | --iter; |
| 463 | } |
| 464 | if (iter->second.empty()) |
| 465 | continue; |
| 466 | parent = iter->second.back(); |
| 467 | iter->second.pop_back(); |
| 468 | } |
| 469 | // If it's a field, then the field is inside a union, so we can safely |
| 470 | // increase its size by converting it to a struct to hold multiple fields. |
| 471 | if (parent->kind == Member::Field) |
| 472 | parent->ConvertToStruct(); |
| 473 | |
| 474 | if (fields.size() == 1) { |
| 475 | uint64_t end_offset = offset + fields.back()->bit_size; |
| 476 | parent->fields.push_back(Elt: std::move(fields.back())); |
| 477 | if (parent->kind == Member::Struct) { |
| 478 | end_offset_map[end_offset].push_back(x: parent); |
| 479 | } else { |
| 480 | lldbassert(parent == &record && |
| 481 | "If parent is union, it must be the top level record." ); |
| 482 | end_offset_map[end_offset].push_back(x: parent->fields.back().get()); |
| 483 | } |
| 484 | } else { |
| 485 | if (parent->kind == Member::Struct) { |
| 486 | parent->fields.push_back(Elt: std::make_unique<Member>(args: Member::Union)); |
| 487 | parent = parent->fields.back().get(); |
| 488 | parent->bit_offset = offset; |
| 489 | } else { |
| 490 | lldbassert(parent == &record && |
| 491 | "If parent is union, it must be the top level record." ); |
| 492 | } |
| 493 | for (auto &field : fields) { |
| 494 | int64_t bit_size = field->bit_size; |
| 495 | parent->fields.push_back(Elt: std::move(field)); |
| 496 | end_offset_map[offset + bit_size].push_back( |
| 497 | x: parent->fields.back().get()); |
| 498 | } |
| 499 | } |
| 500 | } |
| 501 | } |
| 502 | |