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 
20 using namespace llvm;
21 using namespace llvm::pdb;
22 
23 std::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 
31 StreamInfo 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 
40 StreamInfo 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 
50 static inline StreamInfo stream(StreamPurpose Purpose, StringRef Label,
51                                 uint32_t Idx) {
52   return StreamInfo::createStream(Purpose, Label, Idx);
53 }
54 
55 static inline StreamInfo moduleStream(StringRef Label, uint32_t StreamIdx,
56                                       uint32_t Modi) {
57   return StreamInfo::createModuleStream(Label, StreamIdx, Modi);
58 }
59 
60 struct IndexedModuleDescriptor {
61   uint32_t Modi;
62   DbiModuleDescriptor Descriptor;
63 };
64 
65 void 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