1 //===- YAMLOutputStyle.cpp ------------------------------------ *- C++ --*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "YAMLOutputStyle.h"
12 #include "llvm-pdbutil.h"
14 #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
15 #include "llvm/DebugInfo/CodeView/DebugSubsection.h"
16 #include "llvm/DebugInfo/CodeView/DebugUnknownSubsection.h"
17 #include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
18 #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
19 #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
20 #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
21 #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
22 #include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
23 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
24 #include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
25 #include "llvm/DebugInfo/PDB/Native/RawConstants.h"
26 #include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
27 #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
30 using namespace llvm::codeview
;
31 using namespace llvm::pdb
;
33 static bool checkModuleSubsection(opts::ModuleSubsection MS
) {
34 return any_of(opts::pdb2yaml::DumpModuleSubsections
,
35 [=](opts::ModuleSubsection M
) {
36 return M
== MS
|| M
== opts::ModuleSubsection::All
;
40 YAMLOutputStyle::YAMLOutputStyle(PDBFile
&File
)
41 : File(File
), Out(outs()), Obj(File
.getAllocator()) {
42 Out
.setWriteDefaultValues(!opts::pdb2yaml::Minimal
);
45 Error
YAMLOutputStyle::dump() {
46 if (opts::pdb2yaml::StreamDirectory
)
47 opts::pdb2yaml::StreamMetadata
= true;
49 if (auto EC
= dumpFileHeaders())
52 if (auto EC
= dumpStreamMetadata())
55 if (auto EC
= dumpStreamDirectory())
58 if (auto EC
= dumpStringTable())
61 if (auto EC
= dumpPDBStream())
64 if (auto EC
= dumpDbiStream())
67 if (auto EC
= dumpTpiStream())
70 if (auto EC
= dumpIpiStream())
73 if (auto EC
= dumpPublics())
77 return Error::success();
81 Error
YAMLOutputStyle::dumpFileHeaders() {
82 if (opts::pdb2yaml::NoFileHeaders
)
83 return Error::success();
85 yaml::MSFHeaders Headers
;
86 Obj
.Headers
.emplace();
87 Obj
.Headers
->SuperBlock
.NumBlocks
= File
.getBlockCount();
88 Obj
.Headers
->SuperBlock
.BlockMapAddr
= File
.getBlockMapIndex();
89 Obj
.Headers
->SuperBlock
.BlockSize
= File
.getBlockSize();
90 auto Blocks
= File
.getDirectoryBlockArray();
91 Obj
.Headers
->DirectoryBlocks
.assign(Blocks
.begin(), Blocks
.end());
92 Obj
.Headers
->NumDirectoryBlocks
= File
.getNumDirectoryBlocks();
93 Obj
.Headers
->SuperBlock
.NumDirectoryBytes
= File
.getNumDirectoryBytes();
94 Obj
.Headers
->NumStreams
=
95 opts::pdb2yaml::StreamMetadata
? File
.getNumStreams() : 0;
96 Obj
.Headers
->SuperBlock
.FreeBlockMapBlock
= File
.getFreeBlockMapBlock();
97 Obj
.Headers
->SuperBlock
.Unknown1
= File
.getUnknown1();
98 Obj
.Headers
->FileSize
= File
.getFileSize();
100 return Error::success();
103 Error
YAMLOutputStyle::dumpStringTable() {
104 bool RequiresStringTable
= opts::pdb2yaml::DumpModuleFiles
||
105 !opts::pdb2yaml::DumpModuleSubsections
.empty();
106 bool RequestedStringTable
= opts::pdb2yaml::StringTable
;
107 if (!RequiresStringTable
&& !RequestedStringTable
)
108 return Error::success();
110 auto ExpectedST
= File
.getStringTable();
112 return ExpectedST
.takeError();
114 Obj
.StringTable
.emplace();
115 const auto &ST
= ExpectedST
.get();
116 for (auto ID
: ST
.name_ids()) {
117 auto S
= ST
.getStringForID(ID
);
119 return S
.takeError();
122 Obj
.StringTable
->push_back(*S
);
124 return Error::success();
127 Error
YAMLOutputStyle::dumpStreamMetadata() {
128 if (!opts::pdb2yaml::StreamMetadata
)
129 return Error::success();
131 Obj
.StreamSizes
.emplace();
132 Obj
.StreamSizes
->assign(File
.getStreamSizes().begin(),
133 File
.getStreamSizes().end());
134 return Error::success();
137 Error
YAMLOutputStyle::dumpStreamDirectory() {
138 if (!opts::pdb2yaml::StreamDirectory
)
139 return Error::success();
141 auto StreamMap
= File
.getStreamMap();
142 Obj
.StreamMap
.emplace();
143 for (auto &Stream
: StreamMap
) {
144 pdb::yaml::StreamBlockList BlockList
;
145 BlockList
.Blocks
.assign(Stream
.begin(), Stream
.end());
146 Obj
.StreamMap
->push_back(BlockList
);
149 return Error::success();
152 Error
YAMLOutputStyle::dumpPDBStream() {
153 if (!opts::pdb2yaml::PdbStream
)
154 return Error::success();
156 auto IS
= File
.getPDBInfoStream();
158 return IS
.takeError();
160 auto &InfoS
= IS
.get();
161 Obj
.PdbStream
.emplace();
162 Obj
.PdbStream
->Age
= InfoS
.getAge();
163 Obj
.PdbStream
->Guid
= InfoS
.getGuid();
164 Obj
.PdbStream
->Signature
= InfoS
.getSignature();
165 Obj
.PdbStream
->Version
= InfoS
.getVersion();
166 Obj
.PdbStream
->Features
= InfoS
.getFeatureSignatures();
168 return Error::success();
171 static opts::ModuleSubsection
convertSubsectionKind(DebugSubsectionKind K
) {
173 case DebugSubsectionKind::CrossScopeExports
:
174 return opts::ModuleSubsection::CrossScopeExports
;
175 case DebugSubsectionKind::CrossScopeImports
:
176 return opts::ModuleSubsection::CrossScopeImports
;
177 case DebugSubsectionKind::FileChecksums
:
178 return opts::ModuleSubsection::FileChecksums
;
179 case DebugSubsectionKind::InlineeLines
:
180 return opts::ModuleSubsection::InlineeLines
;
181 case DebugSubsectionKind::Lines
:
182 return opts::ModuleSubsection::Lines
;
183 case DebugSubsectionKind::Symbols
:
184 return opts::ModuleSubsection::Symbols
;
185 case DebugSubsectionKind::StringTable
:
186 return opts::ModuleSubsection::StringTable
;
187 case DebugSubsectionKind::FrameData
:
188 return opts::ModuleSubsection::FrameData
;
190 return opts::ModuleSubsection::Unknown
;
192 llvm_unreachable("Unreachable!");
195 Error
YAMLOutputStyle::dumpDbiStream() {
196 if (!opts::pdb2yaml::DbiStream
)
197 return Error::success();
199 if (!File
.hasPDBDbiStream())
200 return Error::success();
202 auto DbiS
= File
.getPDBDbiStream();
204 return DbiS
.takeError();
206 auto &DS
= DbiS
.get();
207 Obj
.DbiStream
.emplace();
208 Obj
.DbiStream
->Age
= DS
.getAge();
209 Obj
.DbiStream
->BuildNumber
= DS
.getBuildNumber();
210 Obj
.DbiStream
->Flags
= DS
.getFlags();
211 Obj
.DbiStream
->MachineType
= DS
.getMachineType();
212 Obj
.DbiStream
->PdbDllRbld
= DS
.getPdbDllRbld();
213 Obj
.DbiStream
->PdbDllVersion
= DS
.getPdbDllVersion();
214 Obj
.DbiStream
->VerHeader
= DS
.getDbiVersion();
215 if (opts::pdb2yaml::DumpModules
) {
216 const auto &Modules
= DS
.modules();
217 for (uint32_t I
= 0; I
< Modules
.getModuleCount(); ++I
) {
218 DbiModuleDescriptor MI
= Modules
.getModuleDescriptor(I
);
220 Obj
.DbiStream
->ModInfos
.emplace_back();
221 yaml::PdbDbiModuleInfo
&DMI
= Obj
.DbiStream
->ModInfos
.back();
223 DMI
.Mod
= MI
.getModuleName();
224 DMI
.Obj
= MI
.getObjFileName();
225 if (opts::pdb2yaml::DumpModuleFiles
) {
226 auto Files
= Modules
.source_files(I
);
227 DMI
.SourceFiles
.assign(Files
.begin(), Files
.end());
230 uint16_t ModiStream
= MI
.getModuleStreamIndex();
231 if (ModiStream
== kInvalidStreamIndex
)
234 auto ModStreamData
= File
.createIndexedStream(ModiStream
);
235 pdb::ModuleDebugStreamRef
ModS(MI
, std::move(ModStreamData
));
236 if (auto EC
= ModS
.reload())
239 auto ExpectedST
= File
.getStringTable();
241 return ExpectedST
.takeError();
242 if (!opts::pdb2yaml::DumpModuleSubsections
.empty() &&
243 ModS
.hasDebugSubsections()) {
244 auto ExpectedChecksums
= ModS
.findChecksumsSubsection();
245 if (!ExpectedChecksums
)
246 return ExpectedChecksums
.takeError();
248 StringsAndChecksumsRef
SC(ExpectedST
->getStringTable(),
251 for (const auto &SS
: ModS
.subsections()) {
252 opts::ModuleSubsection OptionKind
= convertSubsectionKind(SS
.kind());
253 if (!checkModuleSubsection(OptionKind
))
257 CodeViewYAML::YAMLDebugSubsection::fromCodeViewSubection(SC
, SS
);
259 return Converted
.takeError();
260 DMI
.Subsections
.push_back(*Converted
);
264 if (opts::pdb2yaml::DumpModuleSyms
) {
267 DMI
.Modi
->Signature
= ModS
.signature();
268 bool HadError
= false;
269 for (auto &Sym
: ModS
.symbols(&HadError
)) {
270 auto ES
= CodeViewYAML::SymbolRecord::fromCodeViewSymbol(Sym
);
272 return ES
.takeError();
274 DMI
.Modi
->Symbols
.push_back(*ES
);
279 return Error::success();
282 Error
YAMLOutputStyle::dumpTpiStream() {
283 if (!opts::pdb2yaml::TpiStream
)
284 return Error::success();
286 auto TpiS
= File
.getPDBTpiStream();
288 return TpiS
.takeError();
290 auto &TS
= TpiS
.get();
291 Obj
.TpiStream
.emplace();
292 Obj
.TpiStream
->Version
= TS
.getTpiVersion();
293 for (auto &Record
: TS
.types(nullptr)) {
294 auto ExpectedRecord
= CodeViewYAML::LeafRecord::fromCodeViewRecord(Record
);
296 return ExpectedRecord
.takeError();
297 Obj
.TpiStream
->Records
.push_back(*ExpectedRecord
);
300 return Error::success();
303 Error
YAMLOutputStyle::dumpIpiStream() {
304 if (!opts::pdb2yaml::IpiStream
)
305 return Error::success();
307 auto InfoS
= File
.getPDBInfoStream();
309 return InfoS
.takeError();
310 if (!InfoS
->containsIdStream())
311 return Error::success();
313 auto IpiS
= File
.getPDBIpiStream();
315 return IpiS
.takeError();
317 auto &IS
= IpiS
.get();
318 Obj
.IpiStream
.emplace();
319 Obj
.IpiStream
->Version
= IS
.getTpiVersion();
320 for (auto &Record
: IS
.types(nullptr)) {
321 auto ExpectedRecord
= CodeViewYAML::LeafRecord::fromCodeViewRecord(Record
);
323 return ExpectedRecord
.takeError();
325 Obj
.IpiStream
->Records
.push_back(*ExpectedRecord
);
328 return Error::success();
331 Error
YAMLOutputStyle::dumpPublics() {
332 if (!opts::pdb2yaml::PublicsStream
)
333 return Error::success();
335 Obj
.PublicsStream
.emplace();
336 auto ExpectedPublics
= File
.getPDBPublicsStream();
337 if (!ExpectedPublics
) {
338 llvm::consumeError(ExpectedPublics
.takeError());
339 return Error::success();
342 PublicsStream
&Publics
= *ExpectedPublics
;
343 const GSIHashTable
&PublicsTable
= Publics
.getPublicsTable();
345 auto ExpectedSyms
= File
.getPDBSymbolStream();
347 llvm::consumeError(ExpectedSyms
.takeError());
348 return Error::success();
351 BinaryStreamRef SymStream
=
352 ExpectedSyms
->getSymbolArray().getUnderlyingStream();
353 for (uint32_t PubSymOff
: PublicsTable
) {
354 Expected
<CVSymbol
> Sym
= readSymbolFromStream(SymStream
, PubSymOff
);
356 return Sym
.takeError();
357 auto ES
= CodeViewYAML::SymbolRecord::fromCodeViewSymbol(*Sym
);
359 return ES
.takeError();
361 Obj
.PublicsStream
->PubSyms
.push_back(*ES
);
364 return Error::success();
367 void YAMLOutputStyle::flush() {