brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.8 KiB · ff5ae40 Raw
246 lines · cpp
1//===- TpiStream.cpp - PDB Type Info (TPI) Stream 2 Access ----------------===//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 "llvm/DebugInfo/PDB/Native/TpiStream.h"10 11#include "llvm/ADT/iterator_range.h"12#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"13#include "llvm/DebugInfo/CodeView/RecordName.h"14#include "llvm/DebugInfo/CodeView/TypeRecord.h"15#include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h"16#include "llvm/DebugInfo/MSF/MappedBlockStream.h"17#include "llvm/DebugInfo/PDB/Native/Hash.h"18#include "llvm/DebugInfo/PDB/Native/PDBFile.h"19#include "llvm/DebugInfo/PDB/Native/RawConstants.h"20#include "llvm/DebugInfo/PDB/Native/RawError.h"21#include "llvm/DebugInfo/PDB/Native/RawTypes.h"22#include "llvm/DebugInfo/PDB/Native/TpiHashing.h"23#include "llvm/Support/BinaryStreamReader.h"24#include "llvm/Support/Endian.h"25#include "llvm/Support/Error.h"26#include <cstdint>27#include <vector>28 29using namespace llvm;30using namespace llvm::codeview;31using namespace llvm::support;32using namespace llvm::msf;33using namespace llvm::pdb;34 35TpiStream::TpiStream(PDBFile &File, std::unique_ptr<MappedBlockStream> Stream)36    : Pdb(File), Stream(std::move(Stream)) {}37 38TpiStream::~TpiStream() = default;39 40Error TpiStream::reload() {41  BinaryStreamReader Reader(*Stream);42 43  if (Reader.bytesRemaining() < sizeof(TpiStreamHeader))44    return make_error<RawError>(raw_error_code::corrupt_file,45                                "TPI Stream does not contain a header.");46 47  if (Reader.readObject(Header))48    return make_error<RawError>(raw_error_code::corrupt_file,49                                "TPI Stream does not contain a header.");50 51  if (Header->Version != PdbTpiV80)52    return make_error<RawError>(raw_error_code::corrupt_file,53                                "Unsupported TPI Version.");54 55  if (Header->HeaderSize != sizeof(TpiStreamHeader))56    return make_error<RawError>(raw_error_code::corrupt_file,57                                "Corrupt TPI Header size.");58 59  if (Header->HashKeySize != sizeof(ulittle32_t))60    return make_error<RawError>(raw_error_code::corrupt_file,61                                "TPI Stream expected 4 byte hash key size.");62 63  if (Header->NumHashBuckets < MinTpiHashBuckets ||64      Header->NumHashBuckets > MaxTpiHashBuckets)65    return make_error<RawError>(raw_error_code::corrupt_file,66                                "TPI Stream Invalid number of hash buckets.");67 68  // The actual type records themselves come from this stream69  if (auto EC =70          Reader.readSubstream(TypeRecordsSubstream, Header->TypeRecordBytes))71    return EC;72 73  BinaryStreamReader RecordReader(TypeRecordsSubstream.StreamData);74  if (auto EC =75          RecordReader.readArray(TypeRecords, TypeRecordsSubstream.size()))76    return EC;77 78  // Hash indices, hash values, etc come from the hash stream.79  if (Header->HashStreamIndex != kInvalidStreamIndex) {80    auto HS = Pdb.safelyCreateIndexedStream(Header->HashStreamIndex);81    if (!HS) {82      consumeError(HS.takeError());83      return make_error<RawError>(raw_error_code::corrupt_file,84                                  "Invalid TPI hash stream index.");85    }86    BinaryStreamReader HSR(**HS);87 88    // There should be a hash value for every type record, or no hashes at all.89    uint32_t NumHashValues =90        Header->HashValueBuffer.Length / sizeof(ulittle32_t);91    if (NumHashValues != getNumTypeRecords() && NumHashValues != 0)92      return make_error<RawError>(93          raw_error_code::corrupt_file,94          "TPI hash count does not match with the number of type records.");95    HSR.setOffset(Header->HashValueBuffer.Off);96    if (auto EC = HSR.readArray(HashValues, NumHashValues))97      return EC;98 99    HSR.setOffset(Header->IndexOffsetBuffer.Off);100    uint32_t NumTypeIndexOffsets =101        Header->IndexOffsetBuffer.Length / sizeof(TypeIndexOffset);102    if (auto EC = HSR.readArray(TypeIndexOffsets, NumTypeIndexOffsets))103      return EC;104 105    if (Header->HashAdjBuffer.Length > 0) {106      HSR.setOffset(Header->HashAdjBuffer.Off);107      if (auto EC = HashAdjusters.load(HSR))108        return EC;109    }110 111    HashStream = std::move(*HS);112  }113 114  Types = std::make_unique<LazyRandomTypeCollection>(115      TypeRecords, getNumTypeRecords(), getTypeIndexOffsets());116  return Error::success();117}118 119PdbRaw_TpiVer TpiStream::getTpiVersion() const {120  uint32_t Value = Header->Version;121  return static_cast<PdbRaw_TpiVer>(Value);122}123 124uint32_t TpiStream::TypeIndexBegin() const { return Header->TypeIndexBegin; }125 126uint32_t TpiStream::TypeIndexEnd() const { return Header->TypeIndexEnd; }127 128uint32_t TpiStream::getNumTypeRecords() const {129  return TypeIndexEnd() - TypeIndexBegin();130}131 132uint16_t TpiStream::getTypeHashStreamIndex() const {133  return Header->HashStreamIndex;134}135 136uint16_t TpiStream::getTypeHashStreamAuxIndex() const {137  return Header->HashAuxStreamIndex;138}139 140uint32_t TpiStream::getNumHashBuckets() const { return Header->NumHashBuckets; }141uint32_t TpiStream::getHashKeySize() const { return Header->HashKeySize; }142 143void TpiStream::buildHashMap() {144  if (!HashMap.empty())145    return;146  if (HashValues.empty())147    return;148 149  HashMap.resize(Header->NumHashBuckets);150 151  TypeIndex TIB{Header->TypeIndexBegin};152  TypeIndex TIE{Header->TypeIndexEnd};153  while (TIB < TIE) {154    uint32_t HV = HashValues[TIB.toArrayIndex()];155    HashMap[HV].push_back(TIB++);156  }157}158 159std::vector<TypeIndex> TpiStream::findRecordsByName(StringRef Name) const {160  if (!supportsTypeLookup())161    const_cast<TpiStream*>(this)->buildHashMap();162 163  uint32_t Bucket = hashStringV1(Name) % Header->NumHashBuckets;164  if (Bucket > HashMap.size())165    return {};166 167  std::vector<TypeIndex> Result;168  for (TypeIndex TI : HashMap[Bucket]) {169    std::string ThisName = computeTypeName(*Types, TI);170    if (ThisName == Name)171      Result.push_back(TI);172  }173  return Result;174}175 176bool TpiStream::supportsTypeLookup() const { return !HashMap.empty(); }177 178Expected<TypeIndex>179TpiStream::findFullDeclForForwardRef(TypeIndex ForwardRefTI) const {180  if (!supportsTypeLookup())181    const_cast<TpiStream*>(this)->buildHashMap();182 183  CVType F = Types->getType(ForwardRefTI);184  if (!isUdtForwardRef(F))185    return ForwardRefTI;186 187  Expected<TagRecordHash> ForwardTRH = hashTagRecord(F);188  if (!ForwardTRH)189    return ForwardTRH.takeError();190 191  uint32_t BucketIdx = ForwardTRH->FullRecordHash % Header->NumHashBuckets;192 193  for (TypeIndex TI : HashMap[BucketIdx]) {194    CVType CVT = Types->getType(TI);195    if (CVT.kind() != F.kind())196      continue;197 198    Expected<TagRecordHash> FullTRH = hashTagRecord(CVT);199    if (!FullTRH)200      return FullTRH.takeError();201    if (ForwardTRH->FullRecordHash != FullTRH->FullRecordHash)202      continue;203    TagRecord &ForwardTR = ForwardTRH->getRecord();204    TagRecord &FullTR = FullTRH->getRecord();205 206    if (!ForwardTR.hasUniqueName()) {207      if (ForwardTR.getName() == FullTR.getName())208        return TI;209      continue;210    }211 212    if (!FullTR.hasUniqueName())213      continue;214    if (ForwardTR.getUniqueName() == FullTR.getUniqueName())215      return TI;216  }217  return ForwardRefTI;218}219 220codeview::CVType TpiStream::getType(codeview::TypeIndex Index) {221  assert(!Index.isSimple());222  return Types->getType(Index);223}224 225BinarySubstreamRef TpiStream::getTypeRecordsSubstream() const {226  return TypeRecordsSubstream;227}228 229FixedStreamArray<support::ulittle32_t> TpiStream::getHashValues() const {230  return HashValues;231}232 233FixedStreamArray<TypeIndexOffset> TpiStream::getTypeIndexOffsets() const {234  return TypeIndexOffsets;235}236 237HashTable<support::ulittle32_t> &TpiStream::getHashAdjusters() {238  return HashAdjusters;239}240 241CVTypeRange TpiStream::types(bool *HadError) const {242  return make_range(TypeRecords.begin(HadError), TypeRecords.end());243}244 245Error TpiStream::commit() { return Error::success(); }246