1//===- StreamUtil.cpp - PDB stream utilities --------------------*- 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-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "StreamUtil.h"
10
11#include "llvm/ADT/DenseMap.h"
12#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
13#include "llvm/DebugInfo/PDB/Native/DbiModuleList.h"
14#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
15#include "llvm/DebugInfo/PDB/Native/FormatUtil.h"
16#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
17#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
18#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
19
20using namespace llvm;
21using namespace llvm::pdb;
22
23std::string StreamInfo::getLongName() const {
24  if (Purpose == StreamPurpose::NamedStream)
25    return formatv("Named Stream \"{0}\"", Name).str();
26  if (Purpose == StreamPurpose::ModuleStream)
27    return formatv("Module \"{0}\"", Name).str();
28  return Name;
29}
30
31StreamInfo StreamInfo::createStream(StreamPurpose Purpose, StringRef Name,
32                                    uint32_t StreamIndex) {
33  StreamInfo Result;
34  Result.Name = std::string(Name);
35  Result.StreamIndex = StreamIndex;
36  Result.Purpose = Purpose;
37  return Result;
38}
39
40StreamInfo StreamInfo::createModuleStream(StringRef Module,
41                                          uint32_t StreamIndex, uint32_t Modi) {
42  StreamInfo Result;
43  Result.Name = std::string(Module);
44  Result.StreamIndex = StreamIndex;
45  Result.ModuleIndex = Modi;
46  Result.Purpose = StreamPurpose::ModuleStream;
47  return Result;
48}
49
50static inline StreamInfo stream(StreamPurpose Purpose, StringRef Label,
51                                uint32_t Idx) {
52  return StreamInfo::createStream(Purpose, Label, Idx);
53}
54
55static inline StreamInfo moduleStream(StringRef Label, uint32_t StreamIdx,
56                                      uint32_t Modi) {
57  return StreamInfo::createModuleStream(Label, StreamIdx, Modi);
58}
59
60struct IndexedModuleDescriptor {
61  uint32_t Modi;
62  DbiModuleDescriptor Descriptor;
63};
64
65void llvm::pdb::discoverStreamPurposes(PDBFile &File,
66                                       SmallVectorImpl<StreamInfo> &Streams) {
67  // It's OK if we fail to load some of these streams, we still attempt to print
68  // what we can.
69  auto Dbi = File.getPDBDbiStream();
70  auto Tpi = File.getPDBTpiStream();
71  auto Ipi = File.getPDBIpiStream();
72  auto Info = File.getPDBInfoStream();
73
74  uint32_t StreamCount = File.getNumStreams();
75  DenseMap<uint16_t, IndexedModuleDescriptor> ModStreams;
76  DenseMap<uint16_t, std::string> NamedStreams;
77
78  if (Dbi) {
79    const DbiModuleList &Modules = Dbi->modules();
80    for (uint32_t I = 0; I < Modules.getModuleCount(); ++I) {
81      IndexedModuleDescriptor IMD;
82      IMD.Modi = I;
83      IMD.Descriptor = Modules.getModuleDescriptor(I);
84      uint16_t SN = IMD.Descriptor.getModuleStreamIndex();
85      if (SN != kInvalidStreamIndex)
86        ModStreams[SN] = IMD;
87    }
88  }
89  if (Info) {
90    for (auto &NSE : Info->named_streams()) {
91      if (NSE.second != kInvalidStreamIndex)
92        NamedStreams[NSE.second] = std::string(NSE.first());
93    }
94  }
95
96  Streams.resize(StreamCount);
97  for (uint32_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
98    if (StreamIdx == OldMSFDirectory)
99      Streams[StreamIdx] =
100          stream(StreamPurpose::Other, "Old MSF Directory", StreamIdx);
101    else if (StreamIdx == StreamPDB)
102      Streams[StreamIdx] = stream(StreamPurpose::PDB, "PDB Stream", StreamIdx);
103    else if (StreamIdx == StreamDBI)
104      Streams[StreamIdx] = stream(StreamPurpose::DBI, "DBI Stream", StreamIdx);
105    else if (StreamIdx == StreamTPI)
106      Streams[StreamIdx] = stream(StreamPurpose::TPI, "TPI Stream", StreamIdx);
107    else if (StreamIdx == StreamIPI)
108      Streams[StreamIdx] = stream(StreamPurpose::IPI, "IPI Stream", StreamIdx);
109    else if (Dbi && StreamIdx == Dbi->getGlobalSymbolStreamIndex())
110      Streams[StreamIdx] =
111          stream(StreamPurpose::GlobalHash, "Global Symbol Hash", StreamIdx);
112    else if (Dbi && StreamIdx == Dbi->getPublicSymbolStreamIndex())
113      Streams[StreamIdx] =
114          stream(StreamPurpose::PublicHash, "Public Symbol Hash", StreamIdx);
115    else if (Dbi && StreamIdx == Dbi->getSymRecordStreamIndex())
116      Streams[StreamIdx] =
117          stream(StreamPurpose::Symbols, "Symbol Records", StreamIdx);
118    else if (Tpi && StreamIdx == Tpi->getTypeHashStreamIndex())
119      Streams[StreamIdx] =
120          stream(StreamPurpose::TpiHash, "TPI Hash", StreamIdx);
121    else if (Tpi && StreamIdx == Tpi->getTypeHashStreamAuxIndex())
122      Streams[StreamIdx] =
123          stream(StreamPurpose::Other, "TPI Aux Hash", StreamIdx);
124    else if (Ipi && StreamIdx == Ipi->getTypeHashStreamIndex())
125      Streams[StreamIdx] =
126          stream(StreamPurpose::IpiHash, "IPI Hash", StreamIdx);
127    else if (Ipi && StreamIdx == Ipi->getTypeHashStreamAuxIndex())
128      Streams[StreamIdx] =
129          stream(StreamPurpose::Other, "IPI Aux Hash", StreamIdx);
130    else if (Dbi &&
131             StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Exception))
132      Streams[StreamIdx] =
133          stream(StreamPurpose::Other, "Exception Data", StreamIdx);
134    else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Fixup))
135      Streams[StreamIdx] =
136          stream(StreamPurpose::Other, "Fixup Data", StreamIdx);
137    else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::FPO))
138      Streams[StreamIdx] = stream(StreamPurpose::Other, "FPO Data", StreamIdx);
139    else if (Dbi &&
140             StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::NewFPO))
141      Streams[StreamIdx] =
142          stream(StreamPurpose::Other, "New FPO Data", StreamIdx);
143    else if (Dbi &&
144             StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapFromSrc))
145      Streams[StreamIdx] =
146          stream(StreamPurpose::Other, "Omap From Source Data", StreamIdx);
147    else if (Dbi &&
148             StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapToSrc))
149      Streams[StreamIdx] =
150          stream(StreamPurpose::Other, "Omap To Source Data", StreamIdx);
151    else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Pdata))
152      Streams[StreamIdx] = stream(StreamPurpose::Other, "Pdata", StreamIdx);
153    else if (Dbi &&
154             StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdr))
155      Streams[StreamIdx] =
156          stream(StreamPurpose::Other, "Section Header Data", StreamIdx);
157    else if (Dbi &&
158             StreamIdx ==
159                 Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdrOrig))
160      Streams[StreamIdx] = stream(StreamPurpose::Other,
161                                  "Section Header Original Data", StreamIdx);
162    else if (Dbi &&
163             StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::TokenRidMap))
164      Streams[StreamIdx] =
165          stream(StreamPurpose::Other, "Token Rid Data", StreamIdx);
166    else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Xdata))
167      Streams[StreamIdx] = stream(StreamPurpose::Other, "Xdata", StreamIdx);
168    else {
169      auto ModIter = ModStreams.find(StreamIdx);
170      auto NSIter = NamedStreams.find(StreamIdx);
171      if (ModIter != ModStreams.end()) {
172        Streams[StreamIdx] =
173            moduleStream(ModIter->second.Descriptor.getModuleName(), StreamIdx,
174                         ModIter->second.Modi);
175      } else if (NSIter != NamedStreams.end()) {
176        Streams[StreamIdx] =
177            stream(StreamPurpose::NamedStream, NSIter->second, StreamIdx);
178      } else {
179        Streams[StreamIdx] = stream(StreamPurpose::Other, "???", StreamIdx);
180      }
181    }
182  }
183
184  // Consume errors from missing streams.
185  if (!Dbi)
186    consumeError(Dbi.takeError());
187  if (!Tpi)
188    consumeError(Tpi.takeError());
189  if (!Ipi)
190    consumeError(Ipi.takeError());
191  if (!Info)
192    consumeError(Info.takeError());
193}
194