brintos

brintos / llvm-project-archived public Read only

0
0
Text · 20.2 KiB · 46cf9b8 Raw
520 lines · cpp
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 29using namespace llvm::codeview;30using namespace llvm::pdb;31using namespace lldb;32using namespace lldb_private;33using namespace lldb_private::npdb;34 35using Error = llvm::Error;36 37UdtRecordCompleter::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(m_id.index);48  switch (cvt.kind()) {49  case LF_ENUM:50    m_cvr.er.Options = ClassOptions::None;51    llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, m_cvr.er));52    break;53  case LF_UNION:54    m_cvr.ur.Options = ClassOptions::None;55    llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, 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(TypeDeserializer::deserializeAs<ClassRecord>(cvt, 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 71clang::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_id);76 77  CVType udt_cvt = m_index.tpi().getType(ti);78 79  std::unique_ptr<clang::CXXBaseSpecifier> base_spec =80      m_ast_builder.clang().CreateBaseClassSpecifier(81          qt.getAsOpaquePtr(), TranslateMemberAccess(access),82          vtable_idx.has_value(), udt_cvt.kind() == LF_CLASS);83  if (!base_spec)84    return {};85 86  m_bases.push_back(87      std::make_pair(vtable_idx.value_or(0), std::move(base_spec)));88 89  return qt;90}91 92void 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(PdbTypeSymId(type_idx));97  if (method_qt.isNull())98    return;99  CompilerType method_ct = m_ast_builder.ToCompilerType(method_qt);100  TypeSystemClang::RequireCompleteType(method_ct);101  lldb::opaque_compiler_type_t derived_opaque_ty =102      m_derived_ct.GetOpaqueQualType();103  auto iter = m_cxx_record_map.find(derived_opaque_ty);104  if (iter != m_cxx_record_map.end()) {105    if (iter->getSecond().contains({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      derived_opaque_ty, name.data(), /*asm_label=*/{}, method_ct, access_type,115      attrs.isVirtual(), attrs.isStatic(), false, false, false, is_artificial);116 117  m_cxx_record_map[derived_opaque_ty].insert({name, method_ct});118}119 120Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,121                                           BaseClassRecord &base) {122  clang::QualType base_qt =123      AddBaseClassForTypeIndex(base.Type, base.getAccess());124 125  if (base_qt.isNull())126    return llvm::Error::success();127  auto decl =128      m_ast_builder.clang().GetAsCXXRecordDecl(base_qt.getAsOpaquePtr());129  lldbassert(decl);130 131  auto offset = clang::CharUnits::fromQuantity(base.getBaseOffset());132  m_layout.base_offsets.insert(std::make_pair(decl, offset));133 134  return llvm::Error::success();135}136 137Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,138                                           VirtualBaseClassRecord &base) {139  AddBaseClassForTypeIndex(base.BaseType, base.getAccess(), base.VTableIndex);140 141  return Error::success();142}143 144Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,145                                           ListContinuationRecord &cont) {146  return Error::success();147}148 149Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,150                                           VFPtrRecord &vfptr) {151  return Error::success();152}153 154Error UdtRecordCompleter::visitKnownMember(155    CVMemberRecord &cvr, StaticDataMemberRecord &static_data_member) {156  clang::QualType member_type =157      m_ast_builder.GetOrCreateType(PdbTypeSymId(static_data_member.Type));158  if (member_type.isNull())159    return llvm::Error::success();160 161  CompilerType member_ct = m_ast_builder.ToCompilerType(member_type);162 163  lldb::AccessType access =164      TranslateMemberAccess(static_data_member.getAccess());165  auto decl = TypeSystemClang::AddVariableToRecordType(166      m_derived_ct, static_data_member.Name, member_ct, access);167 168  // Static constant members may be a const[expr] declaration.169  // Query the symbol's value as the variable initializer if valid.170  if (member_ct.IsConst() && member_ct.IsCompleteType()) {171    std::string qual_name = decl->getQualifiedNameAsString();172 173    auto results =174        m_index.globals().findRecordsByName(qual_name, m_index.symrecords());175 176    for (const auto &result : results) {177      if (result.second.kind() == SymbolKind::S_CONSTANT) {178        ConstantSym constant(SymbolRecordKind::ConstantSym);179        cantFail(SymbolDeserializer::deserializeAs<ConstantSym>(result.second,180                                                                constant));181 182        clang::QualType qual_type = decl->getType();183        unsigned type_width = decl->getASTContext().getIntWidth(qual_type);184        unsigned constant_width = constant.Value.getBitWidth();185 186        if (qual_type->isIntegralOrEnumerationType()) {187          if (type_width >= constant_width) {188            TypeSystemClang::SetIntegerInitializerForVariable(189                decl, constant.Value.extOrTrunc(type_width));190          } else {191            LLDB_LOG(GetLog(LLDBLog::AST),192                     "Class '{0}' has a member '{1}' of type '{2}' ({3} bits) "193                     "which resolves to a wider constant value ({4} bits). "194                     "Ignoring constant.",195                     m_derived_ct.GetTypeName(), static_data_member.Name,196                     member_ct.GetTypeName(), type_width, constant_width);197          }198        } else {199          lldb::BasicType basic_type_enum = member_ct.GetBasicTypeEnumeration();200          switch (basic_type_enum) {201          case lldb::eBasicTypeFloat:202          case lldb::eBasicTypeDouble:203          case lldb::eBasicTypeLongDouble:204            if (type_width == constant_width) {205              TypeSystemClang::SetFloatingInitializerForVariable(206                  decl, basic_type_enum == lldb::eBasicTypeFloat207                            ? llvm::APFloat(constant.Value.bitsToFloat())208                            : llvm::APFloat(constant.Value.bitsToDouble()));209              decl->setConstexpr(true);210            } else {211              LLDB_LOG(212                  GetLog(LLDBLog::AST),213                  "Class '{0}' has a member '{1}' of type '{2}' ({3} bits) "214                  "which resolves to a constant value of mismatched width "215                  "({4} bits). Ignoring constant.",216                  m_derived_ct.GetTypeName(), static_data_member.Name,217                  member_ct.GetTypeName(), type_width, constant_width);218            }219            break;220          default:221            break;222          }223        }224        break;225      }226    }227  }228 229  // FIXME: Add a PdbSymUid namespace for field list members and update230  // the m_uid_to_decl map with this decl.231  return Error::success();232}233 234Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,235                                           NestedTypeRecord &nested) {236  return Error::success();237}238 239Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,240                                           DataMemberRecord &data_member) {241 242  uint64_t offset = data_member.FieldOffset * 8;243  uint32_t bitfield_width = 0;244 245  TypeIndex ti(data_member.Type);246  if (!ti.isSimple()) {247    CVType cvt = m_index.tpi().getType(ti);248    if (cvt.kind() == LF_BITFIELD) {249      BitFieldRecord bfr;250      llvm::cantFail(TypeDeserializer::deserializeAs<BitFieldRecord>(cvt, bfr));251      offset += bfr.BitOffset;252      bitfield_width = bfr.BitSize;253      ti = bfr.Type;254    }255  }256 257  clang::QualType member_qt = m_ast_builder.GetOrCreateType(PdbTypeSymId(ti));258  if (member_qt.isNull())259    return Error::success();260  TypeSystemClang::RequireCompleteType(m_ast_builder.ToCompilerType(member_qt));261  lldb::AccessType access = TranslateMemberAccess(data_member.getAccess());262  size_t field_size =263      bitfield_width ? bitfield_width : GetSizeOfType(ti, m_index.tpi()) * 8;264  if (field_size == 0)265    return Error::success();266  m_record.CollectMember(data_member.Name, offset, field_size, member_qt, access,267                bitfield_width);268  return Error::success();269}270 271Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,272                                           OneMethodRecord &one_method) {273  AddMethod(one_method.Name, one_method.Type, one_method.getAccess(),274            one_method.getOptions(), one_method.Attrs);275 276  return Error::success();277}278 279Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,280                                           OverloadedMethodRecord &overloaded) {281  TypeIndex method_list_idx = overloaded.MethodList;282 283  CVType method_list_type = m_index.tpi().getType(method_list_idx);284  assert(method_list_type.kind() == LF_METHODLIST);285 286  MethodOverloadListRecord method_list;287  llvm::cantFail(TypeDeserializer::deserializeAs<MethodOverloadListRecord>(288      method_list_type, method_list));289 290  for (const OneMethodRecord &method : method_list.Methods)291    AddMethod(overloaded.Name, method.Type, method.getAccess(),292              method.getOptions(), method.Attrs);293 294  return Error::success();295}296 297Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,298                                           EnumeratorRecord &enumerator) {299  Declaration decl;300  llvm::StringRef name = DropNameScope(enumerator.getName());301 302  m_ast_builder.clang().AddEnumerationValueToEnumerationType(303      m_derived_ct, decl, name.str().c_str(), enumerator.Value);304  return Error::success();305}306 307void UdtRecordCompleter::complete() {308  // Ensure the correct order for virtual bases.309  llvm::stable_sort(m_bases, llvm::less_first());310 311  std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> bases;312  bases.reserve(m_bases.size());313  for (auto &ib : m_bases)314    bases.push_back(std::move(ib.second));315 316  TypeSystemClang &clang = m_ast_builder.clang();317  // Make sure all base classes refer to complete types and not forward318  // declarations. If we don't do this, clang will crash with an319  // assertion in the call to clang_type.TransferBaseClasses()320  for (const auto &base_class : bases) {321    clang::TypeSourceInfo *type_source_info =322        base_class->getTypeSourceInfo();323    if (type_source_info) {324      TypeSystemClang::RequireCompleteType(325          clang.GetType(type_source_info->getType()));326    }327  }328 329  clang.TransferBaseClasses(m_derived_ct.GetOpaqueQualType(), std::move(bases));330 331  clang.AddMethodOverridesForCXXRecordType(m_derived_ct.GetOpaqueQualType());332  FinishRecord();333  TypeSystemClang::BuildIndirectFields(m_derived_ct);334  TypeSystemClang::CompleteTagDeclarationDefinition(m_derived_ct);335 336  if (auto *record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(&m_tag_decl)) {337    m_ast_builder.GetClangASTImporter().SetRecordLayout(record_decl, m_layout);338  }339}340 341uint64_t342UdtRecordCompleter::AddMember(TypeSystemClang &clang, Member *field,343                              uint64_t bit_offset, CompilerType parent_ct,344                              ClangASTImporter::LayoutInfo &parent_layout,345                              clang::DeclContext *parent_decl_ctx) {346  SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(347      clang.GetSymbolFile()->GetBackingSymbolFile());348  clang::FieldDecl *field_decl = nullptr;349  uint64_t bit_size = 0;350  switch (field->kind) {351  case Member::Field: {352    field_decl = TypeSystemClang::AddFieldToRecordType(353        parent_ct, field->name, m_ast_builder.ToCompilerType(field->qt),354        field->access, field->bitfield_width);355    bit_size = field->bit_size;356    break;357  };358  case Member::Struct:359  case Member::Union: {360    clang::TagTypeKind kind = field->kind == Member::Struct361                                  ? clang::TagTypeKind::Struct362                                  : clang::TagTypeKind::Union;363    ClangASTMetadata metadata;364    metadata.SetUserID(pdb->anonymous_id);365    metadata.SetIsDynamicCXXType(false);366    CompilerType record_ct = clang.CreateRecordType(367        parent_decl_ctx, OptionalClangModuleID(), lldb::eAccessPublic, "",368        llvm::to_underlying(kind), lldb::eLanguageTypeC_plus_plus, metadata);369    TypeSystemClang::StartTagDeclarationDefinition(record_ct);370    ClangASTImporter::LayoutInfo layout;371    clang::DeclContext *decl_ctx = clang.GetDeclContextForType(record_ct);372    for (const auto &member : field->fields) {373      uint64_t member_offset = field->kind == Member::Struct374                                   ? member->bit_offset - field->base_offset375                                   : 0;376      uint64_t member_bit_size = AddMember(clang, member.get(), member_offset,377                                          record_ct, layout, decl_ctx);378      if (field->kind == Member::Struct)379        bit_size = std::max(bit_size, member_offset + member_bit_size);380      else381        bit_size = std::max(bit_size, member_bit_size);382    }383    layout.bit_size = bit_size;384    TypeSystemClang::CompleteTagDeclarationDefinition(record_ct);385    clang::RecordDecl *record_decl = clang.GetAsRecordDecl(record_ct);386    m_ast_builder.GetClangASTImporter().SetRecordLayout(record_decl, layout);387    field_decl = TypeSystemClang::AddFieldToRecordType(388        parent_ct, "", record_ct, lldb::eAccessPublic, 0);389    // Mark this record decl as completed.390    DeclStatus status;391    status.resolved = true;392    status.uid = pdb->anonymous_id--;393    m_decl_to_status.insert({record_decl, status});394    break;395  };396  }397  // FIXME: Add a PdbSymUid namespace for field list members and update398  // the m_uid_to_decl map with this decl.399  parent_layout.field_offsets.insert({field_decl, bit_offset});400  return bit_size;401}402 403void UdtRecordCompleter::FinishRecord() {404  TypeSystemClang &clang = m_ast_builder.clang();405  clang::DeclContext *decl_ctx =406      m_ast_builder.GetOrCreateDeclContextForUid(m_id);407  m_record.ConstructRecord();408  // Maybe we should check the construsted record size with the size in pdb. If409  // they mismatch, it might be pdb has fields info missing.410  for (const auto &field : m_record.record.fields) {411    AddMember(clang, field.get(), field->bit_offset, m_derived_ct, m_layout,412             decl_ctx);413  }414}415 416void UdtRecordCompleter::Record::CollectMember(417    llvm::StringRef name, uint64_t offset, uint64_t field_size,418    clang::QualType qt, lldb::AccessType access, uint64_t bitfield_width) {419  fields_map[offset].push_back(std::make_unique<Member>(420      name, offset, field_size, qt, access, bitfield_width));421  if (start_offset > offset)422    start_offset = offset;423}424 425void UdtRecordCompleter::Record::ConstructRecord() {426  // For anonymous unions in a struct, msvc generated pdb doesn't have the427  // entity for that union. So, we need to construct anonymous union and struct428  // based on field offsets. The final AST is likely not matching the exact429  // original AST, but the memory layout is preseved.430  // After we collecting all fields in visitKnownMember, we have all fields in431  // increasing offset order in m_fields. Since we are iterating in increase432  // offset order, if the current offset is equal to m_start_offset, we insert433  // it as direct field of top level record. If the current offset is greater434  // than m_start_offset, we should be able to find a field in end_offset_map435  // whose end offset is less than or equal to current offset. (if not, it might436  // be missing field info. We will ignore the field in this case. e.g. Field A437  // starts at 0 with size 4 bytes, and Field B starts at 2 with size 4 bytes.438  // Normally, there must be something which ends at/before 2.) Then we will439  // append current field to the end of parent record. If parent is struct, we440  // can just grow it. If parent is a field, it's a field inside an union. We441  // convert it into an anonymous struct containing old field and new field.442 443  // The end offset to a vector of field/struct that ends at the offset.444  std::map<uint64_t, std::vector<Member *>> end_offset_map;445  auto is_last_end_offset = [&](auto it) {446    return it != end_offset_map.end() && ++it == end_offset_map.end();447  };448 449  for (auto &pair : fields_map) {450    uint64_t offset = pair.first;451    auto &fields = pair.second;452    lldbassert(offset >= start_offset);453    Member *parent = &record;454    if (offset > start_offset) {455      // Find the field with largest end offset that is <= offset. If it's less456      // than offset, it indicates there are padding bytes between end offset457      // and offset.458      lldbassert(!end_offset_map.empty());459      auto iter = end_offset_map.lower_bound(offset);460      if (iter == end_offset_map.end())461        --iter;462      else if (iter->first > offset) {463        if (iter == end_offset_map.begin())464          continue;465        --iter;466      }467      if (iter->second.empty())468        continue;469 470      // If the new fields come after the already added ones471      // without overlap, go back to the root.472      if (iter->first <= offset && is_last_end_offset(iter)) {473        if (record.kind == Member::Struct) {474          parent = &record;475        } else {476          assert(record.kind == Member::Union &&477                 "Current record must be a union");478          assert(!record.fields.empty());479          // For unions, append the field to the last struct480          parent = record.fields.back().get();481        }482      } else {483        parent = iter->second.back();484        iter->second.pop_back();485      }486    }487    // If it's a field, then the field is inside a union, so we can safely488    // increase its size by converting it to a struct to hold multiple fields.489    if (parent->kind == Member::Field)490      parent->ConvertToStruct();491 492    if (fields.size() == 1) {493      uint64_t end_offset = offset + fields.back()->bit_size;494      parent->fields.push_back(std::move(fields.back()));495      if (parent->kind == Member::Struct) {496        end_offset_map[end_offset].push_back(parent);497      } else {498        lldbassert(parent == &record &&499                   "If parent is union, it must be the top level record.");500        end_offset_map[end_offset].push_back(parent->fields.back().get());501      }502    } else {503      if (parent->kind == Member::Struct) {504        parent->fields.push_back(std::make_unique<Member>(Member::Union));505        parent = parent->fields.back().get();506        parent->bit_offset = offset;507      } else {508        lldbassert(parent == &record &&509                   "If parent is union, it must be the top level record.");510      }511      for (auto &field : fields) {512        int64_t bit_size = field->bit_size;513        parent->fields.push_back(std::move(field));514        end_offset_map[offset + bit_size].push_back(515            parent->fields.back().get());516      }517    }518  }519}520