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(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 | |
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, Name: Label, StreamIndex: Idx); |
53 | } |
54 | |
55 | static inline StreamInfo moduleStream(StringRef Label, uint32_t StreamIdx, |
56 | uint32_t Modi) { |
57 | return StreamInfo::createModuleStream(Module: Label, StreamIndex: 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(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 | |