1 //===- YAMLOutputStyle.cpp ------------------------------------ *- C++ --*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "YAMLOutputStyle.h"
13 #include "llvm-pdbutil.h"
15 #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
16 #include "llvm/DebugInfo/CodeView/DebugSubsection.h"
17 #include "llvm/DebugInfo/CodeView/DebugUnknownSubsection.h"
18 #include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
19 #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
20 #include "llvm/DebugInfo/PDB/Native/DbiStream.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/RawConstants.h"
25 #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
28 using namespace llvm::codeview
;
29 using namespace llvm::pdb
;
31 static bool checkModuleSubsection(opts::ModuleSubsection MS
) {
32 return any_of(opts::pdb2yaml::DumpModuleSubsections
,
33 [=](opts::ModuleSubsection M
) {
34 return M
== MS
|| M
== opts::ModuleSubsection::All
;
38 YAMLOutputStyle::YAMLOutputStyle(PDBFile
&File
)
39 : File(File
), Out(outs()), Obj(File
.getAllocator()) {
40 Out
.setWriteDefaultValues(!opts::pdb2yaml::Minimal
);
43 Error
YAMLOutputStyle::dump() {
44 if (opts::pdb2yaml::StreamDirectory
)
45 opts::pdb2yaml::StreamMetadata
= true;
47 if (auto EC
= dumpFileHeaders())
50 if (auto EC
= dumpStreamMetadata())
53 if (auto EC
= dumpStreamDirectory())
56 if (auto EC
= dumpStringTable())
59 if (auto EC
= dumpPDBStream())
62 if (auto EC
= dumpDbiStream())
65 if (auto EC
= dumpTpiStream())
68 if (auto EC
= dumpIpiStream())
72 return Error::success();
76 Error
YAMLOutputStyle::dumpFileHeaders() {
77 if (opts::pdb2yaml::NoFileHeaders
)
78 return Error::success();
80 yaml::MSFHeaders Headers
;
81 Obj
.Headers
.emplace();
82 Obj
.Headers
->SuperBlock
.NumBlocks
= File
.getBlockCount();
83 Obj
.Headers
->SuperBlock
.BlockMapAddr
= File
.getBlockMapIndex();
84 Obj
.Headers
->SuperBlock
.BlockSize
= File
.getBlockSize();
85 auto Blocks
= File
.getDirectoryBlockArray();
86 Obj
.Headers
->DirectoryBlocks
.assign(Blocks
.begin(), Blocks
.end());
87 Obj
.Headers
->NumDirectoryBlocks
= File
.getNumDirectoryBlocks();
88 Obj
.Headers
->SuperBlock
.NumDirectoryBytes
= File
.getNumDirectoryBytes();
89 Obj
.Headers
->NumStreams
=
90 opts::pdb2yaml::StreamMetadata
? File
.getNumStreams() : 0;
91 Obj
.Headers
->SuperBlock
.FreeBlockMapBlock
= File
.getFreeBlockMapBlock();
92 Obj
.Headers
->SuperBlock
.Unknown1
= File
.getUnknown1();
93 Obj
.Headers
->FileSize
= File
.getFileSize();
95 return Error::success();
98 Error
YAMLOutputStyle::dumpStringTable() {
99 bool RequiresStringTable
= opts::pdb2yaml::DumpModuleFiles
||
100 !opts::pdb2yaml::DumpModuleSubsections
.empty();
101 bool RequestedStringTable
= opts::pdb2yaml::StringTable
;
102 if (!RequiresStringTable
&& !RequestedStringTable
)
103 return Error::success();
105 auto ExpectedST
= File
.getStringTable();
107 return ExpectedST
.takeError();
109 Obj
.StringTable
.emplace();
110 const auto &ST
= ExpectedST
.get();
111 for (auto ID
: ST
.name_ids()) {
112 auto S
= ST
.getStringForID(ID
);
114 return S
.takeError();
117 Obj
.StringTable
->push_back(*S
);
119 return Error::success();
122 Error
YAMLOutputStyle::dumpStreamMetadata() {
123 if (!opts::pdb2yaml::StreamMetadata
)
124 return Error::success();
126 Obj
.StreamSizes
.emplace();
127 Obj
.StreamSizes
->assign(File
.getStreamSizes().begin(),
128 File
.getStreamSizes().end());
129 return Error::success();
132 Error
YAMLOutputStyle::dumpStreamDirectory() {
133 if (!opts::pdb2yaml::StreamDirectory
)
134 return Error::success();
136 auto StreamMap
= File
.getStreamMap();
137 Obj
.StreamMap
.emplace();
138 for (auto &Stream
: StreamMap
) {
139 pdb::yaml::StreamBlockList BlockList
;
140 BlockList
.Blocks
.assign(Stream
.begin(), Stream
.end());
141 Obj
.StreamMap
->push_back(BlockList
);
144 return Error::success();
147 Error
YAMLOutputStyle::dumpPDBStream() {
148 if (!opts::pdb2yaml::PdbStream
)
149 return Error::success();
151 auto IS
= File
.getPDBInfoStream();
153 return IS
.takeError();
155 auto &InfoS
= IS
.get();
156 Obj
.PdbStream
.emplace();
157 Obj
.PdbStream
->Age
= InfoS
.getAge();
158 Obj
.PdbStream
->Guid
= InfoS
.getGuid();
159 Obj
.PdbStream
->Signature
= InfoS
.getSignature();
160 Obj
.PdbStream
->Version
= InfoS
.getVersion();
161 Obj
.PdbStream
->Features
= InfoS
.getFeatureSignatures();
163 return Error::success();
166 static opts::ModuleSubsection
convertSubsectionKind(DebugSubsectionKind K
) {
168 case DebugSubsectionKind::CrossScopeExports
:
169 return opts::ModuleSubsection::CrossScopeExports
;
170 case DebugSubsectionKind::CrossScopeImports
:
171 return opts::ModuleSubsection::CrossScopeImports
;
172 case DebugSubsectionKind::FileChecksums
:
173 return opts::ModuleSubsection::FileChecksums
;
174 case DebugSubsectionKind::InlineeLines
:
175 return opts::ModuleSubsection::InlineeLines
;
176 case DebugSubsectionKind::Lines
:
177 return opts::ModuleSubsection::Lines
;
178 case DebugSubsectionKind::Symbols
:
179 return opts::ModuleSubsection::Symbols
;
180 case DebugSubsectionKind::StringTable
:
181 return opts::ModuleSubsection::StringTable
;
182 case DebugSubsectionKind::FrameData
:
183 return opts::ModuleSubsection::FrameData
;
185 return opts::ModuleSubsection::Unknown
;
187 llvm_unreachable("Unreachable!");
190 Error
YAMLOutputStyle::dumpDbiStream() {
191 if (!opts::pdb2yaml::DbiStream
)
192 return Error::success();
194 if (!File
.hasPDBDbiStream())
195 return Error::success();
197 auto DbiS
= File
.getPDBDbiStream();
199 return DbiS
.takeError();
201 auto &DS
= DbiS
.get();
202 Obj
.DbiStream
.emplace();
203 Obj
.DbiStream
->Age
= DS
.getAge();
204 Obj
.DbiStream
->BuildNumber
= DS
.getBuildNumber();
205 Obj
.DbiStream
->Flags
= DS
.getFlags();
206 Obj
.DbiStream
->MachineType
= DS
.getMachineType();
207 Obj
.DbiStream
->PdbDllRbld
= DS
.getPdbDllRbld();
208 Obj
.DbiStream
->PdbDllVersion
= DS
.getPdbDllVersion();
209 Obj
.DbiStream
->VerHeader
= DS
.getDbiVersion();
210 if (opts::pdb2yaml::DumpModules
) {
211 const auto &Modules
= DS
.modules();
212 for (uint32_t I
= 0; I
< Modules
.getModuleCount(); ++I
) {
213 DbiModuleDescriptor MI
= Modules
.getModuleDescriptor(I
);
215 Obj
.DbiStream
->ModInfos
.emplace_back();
216 yaml::PdbDbiModuleInfo
&DMI
= Obj
.DbiStream
->ModInfos
.back();
218 DMI
.Mod
= MI
.getModuleName();
219 DMI
.Obj
= MI
.getObjFileName();
220 if (opts::pdb2yaml::DumpModuleFiles
) {
221 auto Files
= Modules
.source_files(I
);
222 DMI
.SourceFiles
.assign(Files
.begin(), Files
.end());
225 uint16_t ModiStream
= MI
.getModuleStreamIndex();
226 if (ModiStream
== kInvalidStreamIndex
)
229 auto ModStreamData
= msf::MappedBlockStream::createIndexedStream(
230 File
.getMsfLayout(), File
.getMsfBuffer(), ModiStream
,
231 File
.getAllocator());
233 pdb::ModuleDebugStreamRef
ModS(MI
, std::move(ModStreamData
));
234 if (auto EC
= ModS
.reload())
237 auto ExpectedST
= File
.getStringTable();
239 return ExpectedST
.takeError();
240 if (!opts::pdb2yaml::DumpModuleSubsections
.empty() &&
241 ModS
.hasDebugSubsections()) {
242 auto ExpectedChecksums
= ModS
.findChecksumsSubsection();
243 if (!ExpectedChecksums
)
244 return ExpectedChecksums
.takeError();
246 StringsAndChecksumsRef
SC(ExpectedST
->getStringTable(),
249 for (const auto &SS
: ModS
.subsections()) {
250 opts::ModuleSubsection OptionKind
= convertSubsectionKind(SS
.kind());
251 if (!checkModuleSubsection(OptionKind
))
255 CodeViewYAML::YAMLDebugSubsection::fromCodeViewSubection(SC
, SS
);
257 return Converted
.takeError();
258 DMI
.Subsections
.push_back(*Converted
);
262 if (opts::pdb2yaml::DumpModuleSyms
) {
265 DMI
.Modi
->Signature
= ModS
.signature();
266 bool HadError
= false;
267 for (auto &Sym
: ModS
.symbols(&HadError
)) {
268 auto ES
= CodeViewYAML::SymbolRecord::fromCodeViewSymbol(Sym
);
270 return ES
.takeError();
272 DMI
.Modi
->Symbols
.push_back(*ES
);
277 return Error::success();
280 Error
YAMLOutputStyle::dumpTpiStream() {
281 if (!opts::pdb2yaml::TpiStream
)
282 return Error::success();
284 auto TpiS
= File
.getPDBTpiStream();
286 return TpiS
.takeError();
288 auto &TS
= TpiS
.get();
289 Obj
.TpiStream
.emplace();
290 Obj
.TpiStream
->Version
= TS
.getTpiVersion();
291 for (auto &Record
: TS
.types(nullptr)) {
292 auto ExpectedRecord
= CodeViewYAML::LeafRecord::fromCodeViewRecord(Record
);
294 return ExpectedRecord
.takeError();
295 Obj
.TpiStream
->Records
.push_back(*ExpectedRecord
);
298 return Error::success();
301 Error
YAMLOutputStyle::dumpIpiStream() {
302 if (!opts::pdb2yaml::IpiStream
)
303 return Error::success();
305 auto InfoS
= File
.getPDBInfoStream();
307 return InfoS
.takeError();
308 if (!InfoS
->containsIdStream())
309 return Error::success();
311 auto IpiS
= File
.getPDBIpiStream();
313 return IpiS
.takeError();
315 auto &IS
= IpiS
.get();
316 Obj
.IpiStream
.emplace();
317 Obj
.IpiStream
->Version
= IS
.getTpiVersion();
318 for (auto &Record
: IS
.types(nullptr)) {
319 auto ExpectedRecord
= CodeViewYAML::LeafRecord::fromCodeViewRecord(Record
);
321 return ExpectedRecord
.takeError();
323 Obj
.IpiStream
->Records
.push_back(*ExpectedRecord
);
326 return Error::success();
329 void YAMLOutputStyle::flush() {