brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.6 KiB · c7653b7 Raw
164 lines · cpp
1//===- TypeReferenceTracker.cpp ------------------------------- *- C++ --*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "TypeReferenceTracker.h"10 11#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"12#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"13#include "llvm/DebugInfo/PDB/Native/NativeSession.h"14#include "llvm/DebugInfo/PDB/Native/PDBFile.h"15#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"16#include "llvm/DebugInfo/PDB/Native/TpiStream.h"17#include "llvm/Object/COFF.h"18 19using namespace llvm;20using namespace llvm::pdb;21using namespace llvm::codeview;22 23// LazyRandomTypeCollection doesn't appear to expose the number of records, so24// just iterate up front to find out.25static uint32_t getNumRecordsInCollection(LazyRandomTypeCollection &Types) {26  uint32_t NumTypes = 0;27  for (std::optional<TypeIndex> TI = Types.getFirst(); TI;28       TI = Types.getNext(*TI))29    ++NumTypes;30  return NumTypes;31}32 33TypeReferenceTracker::TypeReferenceTracker(InputFile &File)34    : File(File), Types(File.types()),35      Ids(File.isPdb() ? &File.ids() : nullptr) {36  NumTypeRecords = getNumRecordsInCollection(Types);37  TypeReferenced.resize(NumTypeRecords, false);38 39  // If this is a PDB, ids are stored separately, so make a separate bit vector.40  if (Ids) {41    NumIdRecords = getNumRecordsInCollection(*Ids);42    IdReferenced.resize(NumIdRecords, false);43  }44 45  // Get the TpiStream pointer for forward decl resolution if this is a pdb.46  // Build the hash map to enable resolving forward decls.47  if (File.isPdb()) {48    Tpi = &cantFail(File.pdb().getPDBTpiStream());49    Tpi->buildHashMap();50  }51}52 53void TypeReferenceTracker::mark() {54  // Walk type roots:55  // - globals56  // - modi symbols57  // - LF_UDT_MOD_SRC_LINE? VC always links these in.58  for (const SymbolGroup &SG : File.symbol_groups()) {59    if (File.isObj()) {60      for (const auto &SS : SG.getDebugSubsections()) {61        // FIXME: Are there other type-referencing subsections? Inlinees?62        // Probably for IDs.63        if (SS.kind() != DebugSubsectionKind::Symbols)64          continue;65 66        CVSymbolArray Symbols;67        BinaryStreamReader Reader(SS.getRecordData());68        cantFail(Reader.readArray(Symbols, Reader.getLength()));69        for (const CVSymbol &S : Symbols)70          addTypeRefsFromSymbol(S);71      }72    } else if (SG.hasDebugStream()) {73      for (const CVSymbol &S : SG.getPdbModuleStream().getSymbolArray())74        addTypeRefsFromSymbol(S);75    }76  }77 78  // Walk globals and mark types referenced from globals.79  if (File.isPdb() && File.pdb().hasPDBGlobalsStream()) {80    SymbolStream &SymStream = cantFail(File.pdb().getPDBSymbolStream());81    GlobalsStream &GS = cantFail(File.pdb().getPDBGlobalsStream());82    for (uint32_t PubSymOff : GS.getGlobalsTable()) {83      CVSymbol Sym = SymStream.readRecord(PubSymOff);84      addTypeRefsFromSymbol(Sym);85    }86  }87 88  // FIXME: Should we walk Ids?89}90 91void TypeReferenceTracker::addOneTypeRef(TiRefKind RefKind, TypeIndex RefTI) {92  // If it's simple or already seen, no need to add to work list.93  BitVector &TypeOrIdReferenced =94      (Ids && RefKind == TiRefKind::IndexRef) ? IdReferenced : TypeReferenced;95  if (RefTI.isSimple() || TypeOrIdReferenced.test(RefTI.toArrayIndex()))96    return;97 98  // Otherwise, mark it seen and add it to the work list.99  TypeOrIdReferenced.set(RefTI.toArrayIndex());100  RefWorklist.push_back({RefKind, RefTI});101}102 103void TypeReferenceTracker::addTypeRefsFromSymbol(const CVSymbol &Sym) {104  SmallVector<TiReference, 4> DepList;105  // FIXME: Check for failure.106  discoverTypeIndicesInSymbol(Sym, DepList);107  addReferencedTypes(Sym.content(), DepList);108  markReferencedTypes();109}110 111void TypeReferenceTracker::addReferencedTypes(ArrayRef<uint8_t> RecData,112                                              ArrayRef<TiReference> DepList) {113  for (const auto &Ref : DepList) {114    // FIXME: Report OOB slice instead of truncating.115    ArrayRef<uint8_t> ByteSlice =116        RecData.drop_front(Ref.Offset).take_front(4 * Ref.Count);117    ArrayRef<TypeIndex> TIs(118        reinterpret_cast<const TypeIndex *>(ByteSlice.data()),119        ByteSlice.size() / 4);120 121    // If this is a PDB and this is an item reference, track it in the IPI122    // bitvector. Otherwise, it's a type ref, or there is only one stream.123    for (TypeIndex RefTI : TIs)124      addOneTypeRef(Ref.Kind, RefTI);125  }126}127 128void TypeReferenceTracker::markReferencedTypes() {129  while (!RefWorklist.empty()) {130    TiRefKind RefKind;131    TypeIndex RefTI;132    std::tie(RefKind, RefTI) = RefWorklist.pop_back_val();133    std::optional<CVType> Rec = (Ids && RefKind == TiRefKind::IndexRef)134                                    ? Ids->tryGetType(RefTI)135                                    : Types.tryGetType(RefTI);136    if (!Rec)137      continue; // FIXME: Report a reference to a non-existant type.138 139    SmallVector<TiReference, 4> DepList;140    // FIXME: Check for failure.141    discoverTypeIndices(*Rec, DepList);142    addReferencedTypes(Rec->content(), DepList);143 144    // If this is a tag kind and this is a PDB input, mark the complete type as145    // referenced.146    // FIXME: This limitation makes this feature somewhat useless on object file147    // inputs.148    if (Tpi) {149      switch (Rec->kind()) {150      default:151        break;152      case LF_CLASS:153      case LF_INTERFACE:154      case LF_STRUCTURE:155      case LF_UNION:156      case LF_ENUM:157        addOneTypeRef(TiRefKind::TypeRef,158                      cantFail(Tpi->findFullDeclForForwardRef(RefTI)));159        break;160      }161    }162  }163}164