brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.5 KiB · d1b8c1b Raw
282 lines · cpp
1//===- DbiModuleList.cpp - PDB module information list --------------------===//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/DbiModuleList.h"10#include "llvm/ADT/StringRef.h"11#include "llvm/ADT/iterator_range.h"12#include "llvm/DebugInfo/PDB/Native/RawError.h"13#include "llvm/DebugInfo/PDB/Native/RawTypes.h"14#include "llvm/Support/BinaryStreamReader.h"15#include "llvm/Support/Error.h"16#include <cassert>17#include <cstddef>18#include <cstdint>19 20using namespace llvm;21using namespace llvm::pdb;22 23DbiModuleSourceFilesIterator::DbiModuleSourceFilesIterator(24    const DbiModuleList &Modules, uint32_t Modi, uint16_t Filei)25    : Modules(&Modules), Modi(Modi), Filei(Filei) {26  setValue();27}28 29bool DbiModuleSourceFilesIterator::30operator==(const DbiModuleSourceFilesIterator &R) const {31  // incompatible iterators are never equal32  if (!isCompatible(R))33    return false;34 35  // If they're compatible, and they're both ends, then they're equal.36  if (isEnd() && R.isEnd())37    return true;38 39  // If one is an end and the other is not, they're not equal.40  if (isEnd() != R.isEnd())41    return false;42 43  // Now we know:44  // - They're compatible45  // - They're not *both* end iterators46  // - Their endness is the same.47  // Thus, they're compatible iterators pointing to a valid file on the same48  // module.  All we need to check are the file indices.49  assert(Modules == R.Modules);50  assert(Modi == R.Modi);51  assert(!isEnd());52  assert(!R.isEnd());53 54  return (Filei == R.Filei);55}56 57bool DbiModuleSourceFilesIterator::58operator<(const DbiModuleSourceFilesIterator &R) const {59  assert(isCompatible(R));60 61  // It's not sufficient to compare the file indices, because default62  // constructed iterators could be equal to iterators with valid indices.  To63  // account for this, early-out if they're equal.64  if (*this == R)65    return false;66 67  return Filei < R.Filei;68}69 70std::ptrdiff_t DbiModuleSourceFilesIterator::71operator-(const DbiModuleSourceFilesIterator &R) const {72  assert(isCompatible(R));73  assert(!(*this < R));74 75  // If they're both end iterators, the distance is 0.76  if (isEnd() && R.isEnd())77    return 0;78 79  assert(!R.isEnd());80 81  // At this point, R cannot be end, but *this can, which means that *this82  // might be a universal end iterator with none of its fields set.  So in that83  // case have to rely on R as the authority to figure out how many files there84  // are to compute the distance.85  uint32_t Thisi = Filei;86  if (isEnd()) {87    uint32_t RealModi = R.Modi;88    Thisi = R.Modules->getSourceFileCount(RealModi);89  }90 91  assert(Thisi >= R.Filei);92  return Thisi - R.Filei;93}94 95DbiModuleSourceFilesIterator &DbiModuleSourceFilesIterator::96operator+=(std::ptrdiff_t N) {97  assert(!isEnd());98 99  Filei += N;100  assert(Filei <= Modules->getSourceFileCount(Modi));101  setValue();102  return *this;103}104 105DbiModuleSourceFilesIterator &DbiModuleSourceFilesIterator::106operator-=(std::ptrdiff_t N) {107  // Note that we can subtract from an end iterator, but not a universal end108  // iterator.109  assert(!isUniversalEnd());110 111  assert(N <= Filei);112 113  Filei -= N;114  return *this;115}116 117void DbiModuleSourceFilesIterator::setValue() {118  if (isEnd()) {119    ThisValue = "";120    return;121  }122 123  uint32_t Off = Modules->ModuleInitialFileIndex[Modi] + Filei;124  auto ExpectedValue = Modules->getFileName(Off);125  if (!ExpectedValue) {126    consumeError(ExpectedValue.takeError());127    Filei = Modules->getSourceFileCount(Modi);128  } else129    ThisValue = *ExpectedValue;130}131 132bool DbiModuleSourceFilesIterator::isEnd() const {133  if (isUniversalEnd())134    return true;135 136  assert(Modules);137  assert(Modi <= Modules->getModuleCount());138  assert(Filei <= Modules->getSourceFileCount(Modi));139 140  if (Modi == Modules->getModuleCount())141    return true;142  if (Filei == Modules->getSourceFileCount(Modi))143    return true;144  return false;145}146 147bool DbiModuleSourceFilesIterator::isUniversalEnd() const { return !Modules; }148 149bool DbiModuleSourceFilesIterator::isCompatible(150    const DbiModuleSourceFilesIterator &R) const {151  // Universal iterators are compatible with any other iterator.152  if (isUniversalEnd() || R.isUniversalEnd())153    return true;154 155  // At this point, neither iterator is a universal end iterator, although one156  // or both might be non-universal end iterators.  Regardless, the module index157  // is valid, so they are compatible if and only if they refer to the same158  // module.159  return Modi == R.Modi;160}161 162Error DbiModuleList::initialize(BinaryStreamRef ModInfo,163                                BinaryStreamRef FileInfo) {164  if (auto EC = initializeModInfo(ModInfo))165    return EC;166  if (auto EC = initializeFileInfo(FileInfo))167    return EC;168 169  return Error::success();170}171 172Error DbiModuleList::initializeModInfo(BinaryStreamRef ModInfo) {173  ModInfoSubstream = ModInfo;174 175  if (ModInfo.getLength() == 0)176    return Error::success();177 178  BinaryStreamReader Reader(ModInfo);179 180  if (auto EC = Reader.readArray(Descriptors, ModInfo.getLength()))181    return EC;182 183  return Error::success();184}185 186Error DbiModuleList::initializeFileInfo(BinaryStreamRef FileInfo) {187  FileInfoSubstream = FileInfo;188 189  if (FileInfo.getLength() == 0)190    return Error::success();191 192  BinaryStreamReader FISR(FileInfo);193  if (auto EC = FISR.readObject(FileInfoHeader))194    return EC;195 196  // First is an array of `NumModules` module indices.  This does not seem to be197  // used for anything meaningful, so we ignore it.198  FixedStreamArray<support::ulittle16_t> ModuleIndices;199  if (auto EC = FISR.readArray(ModuleIndices, FileInfoHeader->NumModules))200    return EC;201  if (auto EC = FISR.readArray(ModFileCountArray, FileInfoHeader->NumModules))202    return EC;203 204  // Compute the real number of source files.  We can't trust the value in205  // `FileInfoHeader->NumSourceFiles` because it is a unit16, and the sum of all206  // source file counts might be larger than a unit16.  So we compute the real207  // count by summing up the individual counts.208  uint32_t NumSourceFiles = 0;209  for (auto Count : ModFileCountArray)210    NumSourceFiles += Count;211 212  // In the reference implementation, this array is where the pointer documented213  // at the definition of ModuleInfoHeader::FileNameOffs points to.  Note that214  // although the field in ModuleInfoHeader is ignored this array is not, as it215  // is the authority on where each filename begins in the names buffer.216  if (auto EC = FISR.readArray(FileNameOffsets, NumSourceFiles))217    return EC;218 219  if (auto EC = FISR.readStreamRef(NamesBuffer))220    return EC;221 222  auto DescriptorIter = Descriptors.begin();223  uint32_t NextFileIndex = 0;224  ModuleInitialFileIndex.resize(FileInfoHeader->NumModules);225  ModuleDescriptorOffsets.resize(FileInfoHeader->NumModules);226  for (size_t I = 0; I < FileInfoHeader->NumModules; ++I) {227    assert(DescriptorIter != Descriptors.end());228    ModuleInitialFileIndex[I] = NextFileIndex;229    ModuleDescriptorOffsets[I] = DescriptorIter.offset();230 231    NextFileIndex += ModFileCountArray[I];232    ++DescriptorIter;233  }234 235  assert(DescriptorIter == Descriptors.end());236  assert(NextFileIndex == NumSourceFiles);237 238  return Error::success();239}240 241uint32_t DbiModuleList::getModuleCount() const {242  // Workaround to avoid the crash until upstream issue is fixed:243  // https://github.com/llvm/llvm-project/issues/55214244  return FileInfoHeader ? FileInfoHeader->NumModules : 0;245}246 247uint32_t DbiModuleList::getSourceFileCount() const {248  return FileNameOffsets.size();249}250 251uint16_t DbiModuleList::getSourceFileCount(uint32_t Modi) const {252  return ModFileCountArray[Modi];253}254 255DbiModuleDescriptor DbiModuleList::getModuleDescriptor(uint32_t Modi) const {256  assert(Modi < getModuleCount());257  uint32_t Offset = ModuleDescriptorOffsets[Modi];258  auto Iter = Descriptors.at(Offset);259  assert(Iter != Descriptors.end());260  return *Iter;261}262 263iterator_range<DbiModuleSourceFilesIterator>264DbiModuleList::source_files(uint32_t Modi) const {265  return make_range<DbiModuleSourceFilesIterator>(266      DbiModuleSourceFilesIterator(*this, Modi, 0),267      DbiModuleSourceFilesIterator());268}269 270Expected<StringRef> DbiModuleList::getFileName(uint32_t Index) const {271  BinaryStreamReader Names(NamesBuffer);272  if (Index >= getSourceFileCount())273    return make_error<RawError>(raw_error_code::index_out_of_bounds);274 275  uint32_t FileOffset = FileNameOffsets[Index];276  Names.setOffset(FileOffset);277  StringRef Name;278  if (auto EC = Names.readCString(Name))279    return std::move(EC);280  return Name;281}282