]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp
Merge ^/head r317808 through r317970.
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / llvm-pdbdump / YAMLOutputStyle.cpp
1 //===- YAMLOutputStyle.cpp ------------------------------------ *- C++ --*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "YAMLOutputStyle.h"
11
12 #include "C13DebugFragmentVisitor.h"
13 #include "PdbYaml.h"
14 #include "llvm-pdbdump.h"
15
16 #include "llvm/DebugInfo/CodeView/Line.h"
17 #include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h"
18 #include "llvm/DebugInfo/CodeView/ModuleDebugFragment.h"
19 #include "llvm/DebugInfo/CodeView/ModuleDebugFragmentVisitor.h"
20 #include "llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h"
21 #include "llvm/DebugInfo/CodeView/ModuleDebugLineFragment.h"
22 #include "llvm/DebugInfo/CodeView/ModuleDebugUnknownFragment.h"
23 #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
24 #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
25 #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
26 #include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
27 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
28 #include "llvm/DebugInfo/PDB/Native/RawConstants.h"
29 #include "llvm/DebugInfo/PDB/Native/RawError.h"
30 #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
31
32 using namespace llvm;
33 using namespace llvm::codeview;
34 using namespace llvm::pdb;
35
36 YAMLOutputStyle::YAMLOutputStyle(PDBFile &File)
37     : File(File), Out(outs()), Obj(File.getAllocator()) {
38   Out.setWriteDefaultValues(!opts::pdb2yaml::Minimal);
39 }
40
41 Error YAMLOutputStyle::dump() {
42   if (opts::pdb2yaml::StreamDirectory)
43     opts::pdb2yaml::StreamMetadata = true;
44   if (opts::pdb2yaml::DbiModuleSyms)
45     opts::pdb2yaml::DbiModuleInfo = true;
46
47   if (opts::pdb2yaml::DbiModuleSourceLineInfo)
48     opts::pdb2yaml::DbiModuleSourceFileInfo = true;
49
50   if (opts::pdb2yaml::DbiModuleSourceFileInfo)
51     opts::pdb2yaml::DbiModuleInfo = true;
52
53   if (opts::pdb2yaml::DbiModuleInfo)
54     opts::pdb2yaml::DbiStream = true;
55
56   // Some names from the module source file info get pulled from the string
57   // table, so if we're writing module source info, we have to write the string
58   // table as well.
59   if (opts::pdb2yaml::DbiModuleSourceLineInfo)
60     opts::pdb2yaml::StringTable = true;
61
62   if (auto EC = dumpFileHeaders())
63     return EC;
64
65   if (auto EC = dumpStreamMetadata())
66     return EC;
67
68   if (auto EC = dumpStreamDirectory())
69     return EC;
70
71   if (auto EC = dumpStringTable())
72     return EC;
73
74   if (auto EC = dumpPDBStream())
75     return EC;
76
77   if (auto EC = dumpDbiStream())
78     return EC;
79
80   if (auto EC = dumpTpiStream())
81     return EC;
82
83   if (auto EC = dumpIpiStream())
84     return EC;
85
86   flush();
87   return Error::success();
88 }
89
90 namespace {
91 class C13YamlVisitor : public C13DebugFragmentVisitor {
92 public:
93   C13YamlVisitor(llvm::pdb::yaml::PdbSourceFileInfo &Info, PDBFile &F)
94       : C13DebugFragmentVisitor(F), Info(Info) {}
95
96   Error handleFileChecksums() override {
97     for (const auto &C : *Checksums) {
98       llvm::pdb::yaml::PdbSourceFileChecksumEntry Entry;
99       if (auto Result = getNameFromStringTable(C.FileNameOffset))
100         Entry.FileName = *Result;
101       else
102         return Result.takeError();
103
104       Entry.Kind = C.Kind;
105       Entry.ChecksumBytes.Bytes = C.Checksum;
106       Info.FileChecksums.push_back(Entry);
107     }
108     return Error::success();
109   }
110
111   Error handleLines() override {
112     for (const auto &LF : Lines) {
113       Info.LineFragments.emplace_back();
114       auto &Fragment = Info.LineFragments.back();
115
116       Fragment.CodeSize = LF.header()->CodeSize;
117       Fragment.Flags =
118           static_cast<codeview::LineFlags>(uint16_t(LF.header()->Flags));
119       Fragment.RelocOffset = LF.header()->RelocOffset;
120       Fragment.RelocSegment = LF.header()->RelocSegment;
121
122       for (const auto &L : LF) {
123         Fragment.Blocks.emplace_back();
124         auto &Block = Fragment.Blocks.back();
125
126         if (auto Result = getNameFromChecksumsBuffer(L.NameIndex))
127           Block.FileName = *Result;
128         else
129           return Result.takeError();
130
131         for (const auto &N : L.LineNumbers) {
132           llvm::pdb::yaml::PdbSourceLineEntry Line;
133           Line.Offset = N.Offset;
134           codeview::LineInfo LI(N.Flags);
135           Line.LineStart = LI.getStartLine();
136           Line.EndDelta = LI.getLineDelta();
137           Line.IsStatement = LI.isStatement();
138           Block.Lines.push_back(Line);
139         }
140
141         if (LF.hasColumnInfo()) {
142           for (const auto &C : L.Columns) {
143             llvm::pdb::yaml::PdbSourceColumnEntry Column;
144             Column.StartColumn = C.StartColumn;
145             Column.EndColumn = C.EndColumn;
146             Block.Columns.push_back(Column);
147           }
148         }
149       }
150     }
151     return Error::success();
152   }
153
154   Error handleInlineeLines() override {
155     for (const auto &ILF : InlineeLines) {
156       Info.Inlinees.emplace_back();
157       auto &Inlinee = Info.Inlinees.back();
158
159       Inlinee.HasExtraFiles = ILF.hasExtraFiles();
160       for (const auto &IL : ILF) {
161         Inlinee.Sites.emplace_back();
162         auto &Site = Inlinee.Sites.back();
163         if (auto Result = getNameFromChecksumsBuffer(IL.Header->FileID))
164           Site.FileName = *Result;
165         else
166           return Result.takeError();
167
168         Site.Inlinee = IL.Header->Inlinee;
169         Site.SourceLineNum = IL.Header->SourceLineNum;
170         if (ILF.hasExtraFiles()) {
171           for (const auto &EF : IL.ExtraFiles) {
172             if (auto Result = getNameFromChecksumsBuffer(EF))
173               Site.ExtraFiles.push_back(*Result);
174             else
175               return Result.takeError();
176           }
177         }
178       }
179     }
180     return Error::success();
181   }
182
183 private:
184
185   llvm::pdb::yaml::PdbSourceFileInfo &Info;
186 };
187 }
188
189 Expected<Optional<llvm::pdb::yaml::PdbSourceFileInfo>>
190 YAMLOutputStyle::getFileLineInfo(const pdb::ModuleDebugStreamRef &ModS) {
191   if (!ModS.hasLineInfo())
192     return None;
193
194   yaml::PdbSourceFileInfo Info;
195   C13YamlVisitor Visitor(Info, File);
196   if (auto EC = codeview::visitModuleDebugFragments(ModS.linesAndChecksums(),
197                                                     Visitor))
198     return std::move(EC);
199
200   return Info;
201 }
202
203 Error YAMLOutputStyle::dumpFileHeaders() {
204   if (opts::pdb2yaml::NoFileHeaders)
205     return Error::success();
206
207   yaml::MSFHeaders Headers;
208   Obj.Headers.emplace();
209   Obj.Headers->SuperBlock.NumBlocks = File.getBlockCount();
210   Obj.Headers->SuperBlock.BlockMapAddr = File.getBlockMapIndex();
211   Obj.Headers->SuperBlock.BlockSize = File.getBlockSize();
212   auto Blocks = File.getDirectoryBlockArray();
213   Obj.Headers->DirectoryBlocks.assign(Blocks.begin(), Blocks.end());
214   Obj.Headers->NumDirectoryBlocks = File.getNumDirectoryBlocks();
215   Obj.Headers->SuperBlock.NumDirectoryBytes = File.getNumDirectoryBytes();
216   Obj.Headers->NumStreams =
217       opts::pdb2yaml::StreamMetadata ? File.getNumStreams() : 0;
218   Obj.Headers->SuperBlock.FreeBlockMapBlock = File.getFreeBlockMapBlock();
219   Obj.Headers->SuperBlock.Unknown1 = File.getUnknown1();
220   Obj.Headers->FileSize = File.getFileSize();
221
222   return Error::success();
223 }
224
225 Error YAMLOutputStyle::dumpStringTable() {
226   if (!opts::pdb2yaml::StringTable)
227     return Error::success();
228
229   Obj.StringTable.emplace();
230   auto ExpectedST = File.getStringTable();
231   if (!ExpectedST)
232     return ExpectedST.takeError();
233
234   const auto &ST = ExpectedST.get();
235   for (auto ID : ST.name_ids()) {
236     auto S = ST.getStringForID(ID);
237     if (!S)
238       return S.takeError();
239     if (S->empty())
240       continue;
241     Obj.StringTable->push_back(*S);
242   }
243   return Error::success();
244 }
245
246 Error YAMLOutputStyle::dumpStreamMetadata() {
247   if (!opts::pdb2yaml::StreamMetadata)
248     return Error::success();
249
250   Obj.StreamSizes.emplace();
251   Obj.StreamSizes->assign(File.getStreamSizes().begin(),
252                           File.getStreamSizes().end());
253   return Error::success();
254 }
255
256 Error YAMLOutputStyle::dumpStreamDirectory() {
257   if (!opts::pdb2yaml::StreamDirectory)
258     return Error::success();
259
260   auto StreamMap = File.getStreamMap();
261   Obj.StreamMap.emplace();
262   for (auto &Stream : StreamMap) {
263     pdb::yaml::StreamBlockList BlockList;
264     BlockList.Blocks.assign(Stream.begin(), Stream.end());
265     Obj.StreamMap->push_back(BlockList);
266   }
267
268   return Error::success();
269 }
270
271 Error YAMLOutputStyle::dumpPDBStream() {
272   if (!opts::pdb2yaml::PdbStream)
273     return Error::success();
274
275   auto IS = File.getPDBInfoStream();
276   if (!IS)
277     return IS.takeError();
278
279   auto &InfoS = IS.get();
280   Obj.PdbStream.emplace();
281   Obj.PdbStream->Age = InfoS.getAge();
282   Obj.PdbStream->Guid = InfoS.getGuid();
283   Obj.PdbStream->Signature = InfoS.getSignature();
284   Obj.PdbStream->Version = InfoS.getVersion();
285   Obj.PdbStream->Features = InfoS.getFeatureSignatures();
286
287   return Error::success();
288 }
289
290 Error YAMLOutputStyle::dumpDbiStream() {
291   if (!opts::pdb2yaml::DbiStream)
292     return Error::success();
293
294   auto DbiS = File.getPDBDbiStream();
295   if (!DbiS)
296     return DbiS.takeError();
297
298   auto &DS = DbiS.get();
299   Obj.DbiStream.emplace();
300   Obj.DbiStream->Age = DS.getAge();
301   Obj.DbiStream->BuildNumber = DS.getBuildNumber();
302   Obj.DbiStream->Flags = DS.getFlags();
303   Obj.DbiStream->MachineType = DS.getMachineType();
304   Obj.DbiStream->PdbDllRbld = DS.getPdbDllRbld();
305   Obj.DbiStream->PdbDllVersion = DS.getPdbDllVersion();
306   Obj.DbiStream->VerHeader = DS.getDbiVersion();
307   if (opts::pdb2yaml::DbiModuleInfo) {
308     const auto &Modules = DS.modules();
309     for (uint32_t I = 0; I < Modules.getModuleCount(); ++I) {
310       DbiModuleDescriptor MI = Modules.getModuleDescriptor(I);
311
312       Obj.DbiStream->ModInfos.emplace_back();
313       yaml::PdbDbiModuleInfo &DMI = Obj.DbiStream->ModInfos.back();
314
315       DMI.Mod = MI.getModuleName();
316       DMI.Obj = MI.getObjFileName();
317       if (opts::pdb2yaml::DbiModuleSourceFileInfo) {
318         auto Files = Modules.source_files(I);
319         DMI.SourceFiles.assign(Files.begin(), Files.end());
320       }
321
322       uint16_t ModiStream = MI.getModuleStreamIndex();
323       if (ModiStream == kInvalidStreamIndex)
324         continue;
325
326       auto ModStreamData = msf::MappedBlockStream::createIndexedStream(
327           File.getMsfLayout(), File.getMsfBuffer(), ModiStream);
328
329       pdb::ModuleDebugStreamRef ModS(MI, std::move(ModStreamData));
330       if (auto EC = ModS.reload())
331         return EC;
332
333       if (opts::pdb2yaml::DbiModuleSourceLineInfo) {
334         auto ExpectedInfo = getFileLineInfo(ModS);
335         if (!ExpectedInfo)
336           return ExpectedInfo.takeError();
337         DMI.FileLineInfo = *ExpectedInfo;
338       }
339
340       if (opts::pdb2yaml::DbiModuleSyms) {
341         DMI.Modi.emplace();
342
343         DMI.Modi->Signature = ModS.signature();
344         bool HadError = false;
345         for (auto &Sym : ModS.symbols(&HadError)) {
346           pdb::yaml::PdbSymbolRecord Record{Sym};
347           DMI.Modi->Symbols.push_back(Record);
348         }
349       }
350     }
351   }
352   return Error::success();
353 }
354
355 Error YAMLOutputStyle::dumpTpiStream() {
356   if (!opts::pdb2yaml::TpiStream)
357     return Error::success();
358
359   auto TpiS = File.getPDBTpiStream();
360   if (!TpiS)
361     return TpiS.takeError();
362
363   auto &TS = TpiS.get();
364   Obj.TpiStream.emplace();
365   Obj.TpiStream->Version = TS.getTpiVersion();
366   for (auto &Record : TS.types(nullptr)) {
367     yaml::PdbTpiRecord R;
368     // It's not necessary to set R.RecordData here.  That only exists as a
369     // way to have the `PdbTpiRecord` structure own the memory that `R.Record`
370     // references.  In the case of reading an existing PDB though, that memory
371     // is owned by the backing stream.
372     R.Record = Record;
373     Obj.TpiStream->Records.push_back(R);
374   }
375
376   return Error::success();
377 }
378
379 Error YAMLOutputStyle::dumpIpiStream() {
380   if (!opts::pdb2yaml::IpiStream)
381     return Error::success();
382
383   auto IpiS = File.getPDBIpiStream();
384   if (!IpiS)
385     return IpiS.takeError();
386
387   auto &IS = IpiS.get();
388   Obj.IpiStream.emplace();
389   Obj.IpiStream->Version = IS.getTpiVersion();
390   for (auto &Record : IS.types(nullptr)) {
391     yaml::PdbTpiRecord R;
392     R.Record = Record;
393     Obj.IpiStream->Records.push_back(R);
394   }
395
396   return Error::success();
397 }
398
399 void YAMLOutputStyle::flush() {
400   Out << Obj;
401   outs().flush();
402 }