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
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(Modi: 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(N: StreamCount);
97 for (uint32_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
98 if (StreamIdx == OldMSFDirectory)
99 Streams[StreamIdx] =
100 stream(Purpose: StreamPurpose::Other, Label: "Old MSF Directory", Idx: StreamIdx);
101 else if (StreamIdx == StreamPDB)
102 Streams[StreamIdx] = stream(Purpose: StreamPurpose::PDB, Label: "PDB Stream", Idx: StreamIdx);
103 else if (StreamIdx == StreamDBI)
104 Streams[StreamIdx] = stream(Purpose: StreamPurpose::DBI, Label: "DBI Stream", Idx: StreamIdx);
105 else if (StreamIdx == StreamTPI)
106 Streams[StreamIdx] = stream(Purpose: StreamPurpose::TPI, Label: "TPI Stream", Idx: StreamIdx);
107 else if (StreamIdx == StreamIPI)
108 Streams[StreamIdx] = stream(Purpose: StreamPurpose::IPI, Label: "IPI Stream", Idx: StreamIdx);
109 else if (Dbi && StreamIdx == Dbi->getGlobalSymbolStreamIndex())
110 Streams[StreamIdx] =
111 stream(Purpose: StreamPurpose::GlobalHash, Label: "Global Symbol Hash", Idx: StreamIdx);
112 else if (Dbi && StreamIdx == Dbi->getPublicSymbolStreamIndex())
113 Streams[StreamIdx] =
114 stream(Purpose: StreamPurpose::PublicHash, Label: "Public Symbol Hash", Idx: StreamIdx);
115 else if (Dbi && StreamIdx == Dbi->getSymRecordStreamIndex())
116 Streams[StreamIdx] =
117 stream(Purpose: StreamPurpose::Symbols, Label: "Symbol Records", Idx: StreamIdx);
118 else if (Tpi && StreamIdx == Tpi->getTypeHashStreamIndex())
119 Streams[StreamIdx] =
120 stream(Purpose: StreamPurpose::TpiHash, Label: "TPI Hash", Idx: StreamIdx);
121 else if (Tpi && StreamIdx == Tpi->getTypeHashStreamAuxIndex())
122 Streams[StreamIdx] =
123 stream(Purpose: StreamPurpose::Other, Label: "TPI Aux Hash", Idx: StreamIdx);
124 else if (Ipi && StreamIdx == Ipi->getTypeHashStreamIndex())
125 Streams[StreamIdx] =
126 stream(Purpose: StreamPurpose::IpiHash, Label: "IPI Hash", Idx: StreamIdx);
127 else if (Ipi && StreamIdx == Ipi->getTypeHashStreamAuxIndex())
128 Streams[StreamIdx] =
129 stream(Purpose: StreamPurpose::Other, Label: "IPI Aux Hash", Idx: StreamIdx);
130 else if (Dbi &&
131 StreamIdx == Dbi->getDebugStreamIndex(Type: DbgHeaderType::Exception))
132 Streams[StreamIdx] =
133 stream(Purpose: StreamPurpose::Other, Label: "Exception Data", Idx: StreamIdx);
134 else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(Type: DbgHeaderType::Fixup))
135 Streams[StreamIdx] =
136 stream(Purpose: StreamPurpose::Other, Label: "Fixup Data", Idx: StreamIdx);
137 else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(Type: DbgHeaderType::FPO))
138 Streams[StreamIdx] = stream(Purpose: StreamPurpose::Other, Label: "FPO Data", Idx: StreamIdx);
139 else if (Dbi &&
140 StreamIdx == Dbi->getDebugStreamIndex(Type: DbgHeaderType::NewFPO))
141 Streams[StreamIdx] =
142 stream(Purpose: StreamPurpose::Other, Label: "New FPO Data", Idx: StreamIdx);
143 else if (Dbi &&
144 StreamIdx == Dbi->getDebugStreamIndex(Type: DbgHeaderType::OmapFromSrc))
145 Streams[StreamIdx] =
146 stream(Purpose: StreamPurpose::Other, Label: "Omap From Source Data", Idx: StreamIdx);
147 else if (Dbi &&
148 StreamIdx == Dbi->getDebugStreamIndex(Type: DbgHeaderType::OmapToSrc))
149 Streams[StreamIdx] =
150 stream(Purpose: StreamPurpose::Other, Label: "Omap To Source Data", Idx: StreamIdx);
151 else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(Type: DbgHeaderType::Pdata))
152 Streams[StreamIdx] = stream(Purpose: StreamPurpose::Other, Label: "Pdata", Idx: StreamIdx);
153 else if (Dbi &&
154 StreamIdx == Dbi->getDebugStreamIndex(Type: DbgHeaderType::SectionHdr))
155 Streams[StreamIdx] =
156 stream(Purpose: StreamPurpose::Other, Label: "Section Header Data", Idx: StreamIdx);
157 else if (Dbi &&
158 StreamIdx ==
159 Dbi->getDebugStreamIndex(Type: DbgHeaderType::SectionHdrOrig))
160 Streams[StreamIdx] = stream(Purpose: StreamPurpose::Other,
161 Label: "Section Header Original Data", Idx: StreamIdx);
162 else if (Dbi &&
163 StreamIdx == Dbi->getDebugStreamIndex(Type: DbgHeaderType::TokenRidMap))
164 Streams[StreamIdx] =
165 stream(Purpose: StreamPurpose::Other, Label: "Token Rid Data", Idx: StreamIdx);
166 else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(Type: DbgHeaderType::Xdata))
167 Streams[StreamIdx] = stream(Purpose: StreamPurpose::Other, Label: "Xdata", Idx: StreamIdx);
168 else {
169 auto ModIter = ModStreams.find(Val: StreamIdx);
170 auto NSIter = NamedStreams.find(Val: StreamIdx);
171 if (ModIter != ModStreams.end()) {
172 Streams[StreamIdx] =
173 moduleStream(Label: ModIter->second.Descriptor.getModuleName(), StreamIdx,
174 Modi: ModIter->second.Modi);
175 } else if (NSIter != NamedStreams.end()) {
176 Streams[StreamIdx] =
177 stream(Purpose: StreamPurpose::NamedStream, Label: NSIter->second, Idx: StreamIdx);
178 } else {
179 Streams[StreamIdx] = stream(Purpose: StreamPurpose::Other, Label: "???", Idx: StreamIdx);
180 }
181 }
182 }
183
184 // Consume errors from missing streams.
185 if (!Dbi)
186 consumeError(Err: Dbi.takeError());
187 if (!Tpi)
188 consumeError(Err: Tpi.takeError());
189 if (!Ipi)
190 consumeError(Err: Ipi.takeError());
191 if (!Info)
192 consumeError(Err: Info.takeError());
193}
194