1 //===- DbiModuleDescriptorBuilder.cpp - PDB Mod Info Creation ---*- 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 "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h"
10 
11 #include "llvm/ADT/ArrayRef.h"
12 #include "llvm/BinaryFormat/COFF.h"
13 #include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
14 #include "llvm/DebugInfo/MSF/MSFBuilder.h"
15 #include "llvm/DebugInfo/MSF/MSFCommon.h"
16 #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
17 #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
18 #include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h"
19 #include "llvm/DebugInfo/PDB/Native/RawConstants.h"
20 #include "llvm/DebugInfo/PDB/Native/RawError.h"
21 #include "llvm/Support/BinaryStreamWriter.h"
22 
23 using namespace llvm;
24 using namespace llvm::codeview;
25 using namespace llvm::msf;
26 using namespace llvm::pdb;
27 
28 static uint32_t calculateDiSymbolStreamSize(uint32_t SymbolByteSize,
29                                             uint32_t C13Size) {
30   uint32_t Size = sizeof(uint32_t);   // Signature
31   Size += alignTo(SymbolByteSize, 4); // Symbol Data
32   Size += 0;                          // TODO: Layout.C11Bytes
33   Size += C13Size;                    // C13 Debug Info Size
34   Size += sizeof(uint32_t);           // GlobalRefs substream size (always 0)
35   Size += 0;                          // GlobalRefs substream bytes
36   return Size;
37 }
38 
39 DbiModuleDescriptorBuilder::DbiModuleDescriptorBuilder(StringRef ModuleName,
40                                                        uint32_t ModIndex,
41                                                        msf::MSFBuilder &Msf)
42     : MSF(Msf), ModuleName(std::string(ModuleName)) {
43   ::memset(&Layout, 0, sizeof(Layout));
44   Layout.Mod = ModIndex;
45 }
46 
47 DbiModuleDescriptorBuilder::~DbiModuleDescriptorBuilder() {}
48 
49 uint16_t DbiModuleDescriptorBuilder::getStreamIndex() const {
50   return Layout.ModDiStream;
51 }
52 
53 void DbiModuleDescriptorBuilder::setObjFileName(StringRef Name) {
54   ObjFileName = std::string(Name);
55 }
56 
57 void DbiModuleDescriptorBuilder::setPdbFilePathNI(uint32_t NI) {
58   PdbFilePathNI = NI;
59 }
60 
61 void DbiModuleDescriptorBuilder::setFirstSectionContrib(
62     const SectionContrib &SC) {
63   Layout.SC = SC;
64 }
65 
66 void DbiModuleDescriptorBuilder::addSymbol(CVSymbol Symbol) {
67   // Defer to the bulk API. It does the same thing.
68   addSymbolsInBulk(Symbol.data());
69 }
70 
71 void DbiModuleDescriptorBuilder::addSymbolsInBulk(
72     ArrayRef<uint8_t> BulkSymbols) {
73   // Do nothing for empty runs of symbols.
74   if (BulkSymbols.empty())
75     return;
76 
77   Symbols.push_back(SymbolListWrapper(BulkSymbols));
78   // Symbols written to a PDB file are required to be 4 byte aligned. The same
79   // is not true of object files.
80   assert(BulkSymbols.size() % alignOf(CodeViewContainer::Pdb) == 0 &&
81          "Invalid Symbol alignment!");
82   SymbolByteSize += BulkSymbols.size();
83 }
84 
85 void DbiModuleDescriptorBuilder::addUnmergedSymbols(void *SymSrc,
86                                                     uint32_t SymLength) {
87   assert(SymLength > 0);
88   Symbols.push_back(SymbolListWrapper(SymSrc, SymLength));
89 
90   // Symbols written to a PDB file are required to be 4 byte aligned. The same
91   // is not true of object files.
92   assert(SymLength % alignOf(CodeViewContainer::Pdb) == 0 &&
93          "Invalid Symbol alignment!");
94   SymbolByteSize += SymLength;
95 }
96 
97 void DbiModuleDescriptorBuilder::addSourceFile(StringRef Path) {
98   SourceFiles.push_back(std::string(Path));
99 }
100 
101 uint32_t DbiModuleDescriptorBuilder::calculateC13DebugInfoSize() const {
102   uint32_t Result = 0;
103   for (const auto &Builder : C13Builders) {
104     Result += Builder.calculateSerializedLength();
105   }
106   return Result;
107 }
108 
109 uint32_t DbiModuleDescriptorBuilder::calculateSerializedLength() const {
110   uint32_t L = sizeof(Layout);
111   uint32_t M = ModuleName.size() + 1;
112   uint32_t O = ObjFileName.size() + 1;
113   return alignTo(L + M + O, sizeof(uint32_t));
114 }
115 
116 void DbiModuleDescriptorBuilder::finalize() {
117   Layout.FileNameOffs = 0; // TODO: Fix this
118   Layout.Flags = 0;        // TODO: Fix this
119   Layout.C11Bytes = 0;
120   Layout.C13Bytes = calculateC13DebugInfoSize();
121   (void)Layout.Mod;         // Set in constructor
122   (void)Layout.ModDiStream; // Set in finalizeMsfLayout
123   Layout.NumFiles = SourceFiles.size();
124   Layout.PdbFilePathNI = PdbFilePathNI;
125   Layout.SrcFileNameNI = 0;
126 
127   // This value includes both the signature field as well as the record bytes
128   // from the symbol stream.
129   Layout.SymBytes =
130       Layout.ModDiStream == kInvalidStreamIndex ? 0 : getNextSymbolOffset();
131 }
132 
133 Error DbiModuleDescriptorBuilder::finalizeMsfLayout() {
134   this->Layout.ModDiStream = kInvalidStreamIndex;
135   uint32_t C13Size = calculateC13DebugInfoSize();
136   if (!C13Size && !SymbolByteSize)
137     return Error::success();
138   auto ExpectedSN =
139       MSF.addStream(calculateDiSymbolStreamSize(SymbolByteSize, C13Size));
140   if (!ExpectedSN)
141     return ExpectedSN.takeError();
142   Layout.ModDiStream = *ExpectedSN;
143   return Error::success();
144 }
145 
146 Error DbiModuleDescriptorBuilder::commit(BinaryStreamWriter &ModiWriter) {
147   // We write the Modi record to the `ModiWriter`, but we additionally write its
148   // symbol stream to a brand new stream.
149   if (auto EC = ModiWriter.writeObject(Layout))
150     return EC;
151   if (auto EC = ModiWriter.writeCString(ModuleName))
152     return EC;
153   if (auto EC = ModiWriter.writeCString(ObjFileName))
154     return EC;
155   if (auto EC = ModiWriter.padToAlignment(sizeof(uint32_t)))
156     return EC;
157   return Error::success();
158 }
159 
160 Error DbiModuleDescriptorBuilder::commitSymbolStream(
161     const msf::MSFLayout &MsfLayout, WritableBinaryStreamRef MsfBuffer) {
162   if (Layout.ModDiStream == kInvalidStreamIndex)
163     return Error::success();
164 
165   auto NS = WritableMappedBlockStream::createIndexedStream(
166       MsfLayout, MsfBuffer, Layout.ModDiStream, MSF.getAllocator());
167   WritableBinaryStreamRef Ref(*NS);
168   BinaryStreamWriter SymbolWriter(Ref);
169   // Write the symbols.
170   if (auto EC = SymbolWriter.writeInteger<uint32_t>(COFF::DEBUG_SECTION_MAGIC))
171     return EC;
172   for (const SymbolListWrapper &Sym : Symbols) {
173     if (Sym.NeedsToBeMerged) {
174       assert(MergeSymsCallback);
175       if (auto EC = MergeSymsCallback(MergeSymsCtx, Sym.SymPtr, SymbolWriter))
176         return EC;
177     } else {
178       if (auto EC = SymbolWriter.writeBytes(Sym.asArray()))
179         return EC;
180     }
181   }
182 
183   // Apply the string table fixups.
184   auto SavedOffset = SymbolWriter.getOffset();
185   for (const StringTableFixup &Fixup : StringTableFixups) {
186     SymbolWriter.setOffset(Fixup.SymOffsetOfReference);
187     if (auto E = SymbolWriter.writeInteger<uint32_t>(Fixup.StrTabOffset))
188       return E;
189   }
190   SymbolWriter.setOffset(SavedOffset);
191 
192   assert(SymbolWriter.getOffset() % alignOf(CodeViewContainer::Pdb) == 0 &&
193          "Invalid debug section alignment!");
194   // TODO: Write C11 Line data
195   for (const auto &Builder : C13Builders) {
196     if (auto EC = Builder.commit(SymbolWriter, CodeViewContainer::Pdb))
197       return EC;
198   }
199 
200   // TODO: Figure out what GlobalRefs substream actually is and populate it.
201   if (auto EC = SymbolWriter.writeInteger<uint32_t>(0))
202     return EC;
203   if (SymbolWriter.bytesRemaining() > 0)
204     return make_error<RawError>(raw_error_code::stream_too_long);
205 
206   return Error::success();
207 }
208 
209 void DbiModuleDescriptorBuilder::addDebugSubsection(
210     std::shared_ptr<DebugSubsection> Subsection) {
211   assert(Subsection);
212   C13Builders.push_back(DebugSubsectionRecordBuilder(std::move(Subsection)));
213 }
214 
215 void DbiModuleDescriptorBuilder::addDebugSubsection(
216     const DebugSubsectionRecord &SubsectionContents) {
217   C13Builders.push_back(DebugSubsectionRecordBuilder(SubsectionContents));
218 }
219