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(Fmt: "Named Stream \"{0}\"", Vals: Name).str();
26 if (Purpose == StreamPurpose::ModuleStream)
27 return formatv(Fmt: "Module \"{0}\"", Vals: 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, Name: Label, StreamIndex: Idx);
53}
54
55static inline StreamInfo moduleStream(StringRef Label, uint32_t StreamIdx,
56 uint32_t Modi) {
57 return StreamInfo::createModuleStream(Module: Label, StreamIndex: 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 auto Dxc = File.getDXContainerStream();
74
75 uint32_t StreamCount = File.getNumStreams();
76 DenseMap<uint16_t, IndexedModuleDescriptor> ModStreams;
77 DenseMap<uint16_t, std::string> NamedStreams;
78
79 if (Dbi) {
80 const DbiModuleList &Modules = Dbi->modules();
81 for (uint32_t I = 0; I < Modules.getModuleCount(); ++I) {
82 IndexedModuleDescriptor IMD;
83 IMD.Modi = I;
84 IMD.Descriptor = Modules.getModuleDescriptor(Modi: I);
85 uint16_t SN = IMD.Descriptor.getModuleStreamIndex();
86 if (SN != kInvalidStreamIndex)
87 ModStreams[SN] = IMD;
88 }
89 }
90 if (Info) {
91 for (auto &NSE : Info->named_streams()) {
92 if (NSE.second != kInvalidStreamIndex)
93 NamedStreams[NSE.second] = std::string(NSE.first());
94 }
95 }
96
97 Streams.resize(N: StreamCount);
98 for (uint32_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
99 if (StreamIdx == OldMSFDirectory)
100 Streams[StreamIdx] =
101 stream(Purpose: StreamPurpose::Other, Label: "Old MSF Directory", Idx: StreamIdx);
102 else if (StreamIdx == StreamPDB)
103 Streams[StreamIdx] = stream(Purpose: StreamPurpose::PDB, Label: "PDB Stream", Idx: StreamIdx);
104 else if (StreamIdx == StreamDBI)
105 Streams[StreamIdx] = stream(Purpose: StreamPurpose::DBI, Label: "DBI Stream", Idx: StreamIdx);
106 else if (StreamIdx == StreamTPI)
107 Streams[StreamIdx] = stream(Purpose: StreamPurpose::TPI, Label: "TPI Stream", Idx: StreamIdx);
108 else if (StreamIdx == StreamIPI)
109 Streams[StreamIdx] = stream(Purpose: StreamPurpose::IPI, Label: "IPI Stream", Idx: StreamIdx);
110 else if (Dxc && StreamIdx == StreamDXContainer)
111 Streams[StreamIdx] =
112 stream(Purpose: StreamPurpose::DXContainer, Label: "DXContainer Stream", Idx: StreamIdx);
113 else if (Dbi && StreamIdx == Dbi->getGlobalSymbolStreamIndex())
114 Streams[StreamIdx] =
115 stream(Purpose: StreamPurpose::GlobalHash, Label: "Global Symbol Hash", Idx: StreamIdx);
116 else if (Dbi && StreamIdx == Dbi->getPublicSymbolStreamIndex())
117 Streams[StreamIdx] =
118 stream(Purpose: StreamPurpose::PublicHash, Label: "Public Symbol Hash", Idx: StreamIdx);
119 else if (Dbi && StreamIdx == Dbi->getSymRecordStreamIndex())
120 Streams[StreamIdx] =
121 stream(Purpose: StreamPurpose::Symbols, Label: "Symbol Records", Idx: StreamIdx);
122 else if (Tpi && StreamIdx == Tpi->getTypeHashStreamIndex())
123 Streams[StreamIdx] =
124 stream(Purpose: StreamPurpose::TpiHash, Label: "TPI Hash", Idx: StreamIdx);
125 else if (Tpi && StreamIdx == Tpi->getTypeHashStreamAuxIndex())
126 Streams[StreamIdx] =
127 stream(Purpose: StreamPurpose::Other, Label: "TPI Aux Hash", Idx: StreamIdx);
128 else if (Ipi && StreamIdx == Ipi->getTypeHashStreamIndex())
129 Streams[StreamIdx] =
130 stream(Purpose: StreamPurpose::IpiHash, Label: "IPI Hash", Idx: StreamIdx);
131 else if (Ipi && StreamIdx == Ipi->getTypeHashStreamAuxIndex())
132 Streams[StreamIdx] =
133 stream(Purpose: StreamPurpose::Other, Label: "IPI Aux Hash", Idx: StreamIdx);
134 else if (Dbi &&
135 StreamIdx == Dbi->getDebugStreamIndex(Type: DbgHeaderType::Exception))
136 Streams[StreamIdx] =
137 stream(Purpose: StreamPurpose::Other, Label: "Exception Data", Idx: StreamIdx);
138 else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(Type: DbgHeaderType::Fixup))
139 Streams[StreamIdx] =
140 stream(Purpose: StreamPurpose::Other, Label: "Fixup Data", Idx: StreamIdx);
141 else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(Type: DbgHeaderType::FPO))
142 Streams[StreamIdx] = stream(Purpose: StreamPurpose::Other, Label: "FPO Data", Idx: StreamIdx);
143 else if (Dbi &&
144 StreamIdx == Dbi->getDebugStreamIndex(Type: DbgHeaderType::NewFPO))
145 Streams[StreamIdx] =
146 stream(Purpose: StreamPurpose::Other, Label: "New FPO Data", Idx: StreamIdx);
147 else if (Dbi &&
148 StreamIdx == Dbi->getDebugStreamIndex(Type: DbgHeaderType::OmapFromSrc))
149 Streams[StreamIdx] =
150 stream(Purpose: StreamPurpose::Other, Label: "Omap From Source Data", Idx: StreamIdx);
151 else if (Dbi &&
152 StreamIdx == Dbi->getDebugStreamIndex(Type: DbgHeaderType::OmapToSrc))
153 Streams[StreamIdx] =
154 stream(Purpose: StreamPurpose::Other, Label: "Omap To Source Data", Idx: StreamIdx);
155 else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(Type: DbgHeaderType::Pdata))
156 Streams[StreamIdx] = stream(Purpose: StreamPurpose::Other, Label: "Pdata", Idx: StreamIdx);
157 else if (Dbi &&
158 StreamIdx == Dbi->getDebugStreamIndex(Type: DbgHeaderType::SectionHdr))
159 Streams[StreamIdx] =
160 stream(Purpose: StreamPurpose::Other, Label: "Section Header Data", Idx: StreamIdx);
161 else if (Dbi &&
162 StreamIdx ==
163 Dbi->getDebugStreamIndex(Type: DbgHeaderType::SectionHdrOrig))
164 Streams[StreamIdx] = stream(Purpose: StreamPurpose::Other,
165 Label: "Section Header Original Data", Idx: StreamIdx);
166 else if (Dbi &&
167 StreamIdx == Dbi->getDebugStreamIndex(Type: DbgHeaderType::TokenRidMap))
168 Streams[StreamIdx] =
169 stream(Purpose: StreamPurpose::Other, Label: "Token Rid Data", Idx: StreamIdx);
170 else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(Type: DbgHeaderType::Xdata))
171 Streams[StreamIdx] = stream(Purpose: StreamPurpose::Other, Label: "Xdata", Idx: StreamIdx);
172 else {
173 auto ModIter = ModStreams.find(Val: StreamIdx);
174 auto NSIter = NamedStreams.find(Val: StreamIdx);
175 if (ModIter != ModStreams.end()) {
176 Streams[StreamIdx] =
177 moduleStream(Label: ModIter->second.Descriptor.getModuleName(), StreamIdx,
178 Modi: ModIter->second.Modi);
179 } else if (NSIter != NamedStreams.end()) {
180 Streams[StreamIdx] =
181 stream(Purpose: StreamPurpose::NamedStream, Label: NSIter->second, Idx: StreamIdx);
182 } else {
183 Streams[StreamIdx] = stream(Purpose: StreamPurpose::Other, Label: "???", Idx: StreamIdx);
184 }
185 }
186 }
187
188 // Consume errors from missing streams.
189 if (!Dbi)
190 consumeError(Err: Dbi.takeError());
191 if (!Tpi)
192 consumeError(Err: Tpi.takeError());
193 if (!Ipi)
194 consumeError(Err: Ipi.takeError());
195 if (!Info)
196 consumeError(Err: Info.takeError());
197 if (!Dxc)
198 consumeError(Err: Dxc.takeError());
199}
200