1 //===- DbiModuleDescriptorBuilder.h - PDB module information ----*- 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 #ifndef LLVM_DEBUGINFO_PDB_NATIVE_DBIMODULEDESCRIPTORBUILDER_H
10 #define LLVM_DEBUGINFO_PDB_NATIVE_DBIMODULEDESCRIPTORBUILDER_H
11 
12 #include "llvm/ADT/ArrayRef.h"
13 #include "llvm/ADT/StringRef.h"
14 #include "llvm/DebugInfo/CodeView/CVRecord.h"
15 #include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
16 #include "llvm/DebugInfo/PDB/Native/RawTypes.h"
17 #include "llvm/Support/BinaryStreamRef.h"
18 #include "llvm/Support/Error.h"
19 #include <cstdint>
20 #include <string>
21 #include <vector>
22 
23 namespace llvm {
24 class BinaryStreamWriter;
25 namespace codeview {
26 class DebugSubsection;
27 }
28 
29 namespace msf {
30 class MSFBuilder;
31 struct MSFLayout;
32 }
33 namespace pdb {
34 
35 // Represents merged or unmerged symbols. Merged symbols can be written to the
36 // output file as is, but unmerged symbols must be rewritten first. In either
37 // case, the size must be known up front.
38 struct SymbolListWrapper {
39   explicit SymbolListWrapper(ArrayRef<uint8_t> Syms)
40       : SymPtr(const_cast<uint8_t *>(Syms.data())), SymSize(Syms.size()),
41         NeedsToBeMerged(false) {}
42   explicit SymbolListWrapper(void *SymSrc, uint32_t Length)
43       : SymPtr(SymSrc), SymSize(Length), NeedsToBeMerged(true) {}
44 
45   ArrayRef<uint8_t> asArray() const {
46     return ArrayRef<uint8_t>(static_cast<const uint8_t *>(SymPtr), SymSize);
47   }
48 
49   uint32_t size() const { return SymSize; }
50 
51   void *SymPtr = nullptr;
52   uint32_t SymSize = 0;
53   bool NeedsToBeMerged = false;
54 };
55 
56 /// Represents a string table reference at some offset in the module symbol
57 /// stream.
58 struct StringTableFixup {
59   uint32_t StrTabOffset = 0;
60   uint32_t SymOffsetOfReference = 0;
61 };
62 
63 class DbiModuleDescriptorBuilder {
64   friend class DbiStreamBuilder;
65 
66 public:
67   DbiModuleDescriptorBuilder(StringRef ModuleName, uint32_t ModIndex,
68                              msf::MSFBuilder &Msf);
69   ~DbiModuleDescriptorBuilder();
70 
71   DbiModuleDescriptorBuilder(const DbiModuleDescriptorBuilder &) = delete;
72   DbiModuleDescriptorBuilder &
73   operator=(const DbiModuleDescriptorBuilder &) = delete;
74 
75   void setPdbFilePathNI(uint32_t NI);
76   void setObjFileName(StringRef Name);
77 
78   // Callback to merge one source of unmerged symbols.
79   using MergeSymbolsCallback = Error (*)(void *Ctx, void *Symbols,
80                                          BinaryStreamWriter &Writer);
81 
82   void setMergeSymbolsCallback(void *Ctx, MergeSymbolsCallback Callback) {
83     MergeSymsCtx = Ctx;
84     MergeSymsCallback = Callback;
85   }
86 
87   void setStringTableFixups(std::vector<StringTableFixup> &&Fixups) {
88     StringTableFixups = std::move(Fixups);
89   }
90 
91   void setFirstSectionContrib(const SectionContrib &SC);
92   void addSymbol(codeview::CVSymbol Symbol);
93   void addSymbolsInBulk(ArrayRef<uint8_t> BulkSymbols);
94 
95   // Add symbols of known size which will be merged (rewritten) when committing
96   // the PDB to disk.
97   void addUnmergedSymbols(void *SymSrc, uint32_t SymLength);
98 
99   void
100   addDebugSubsection(std::shared_ptr<codeview::DebugSubsection> Subsection);
101 
102   void
103   addDebugSubsection(const codeview::DebugSubsectionRecord &SubsectionContents);
104 
105   uint16_t getStreamIndex() const;
106   StringRef getModuleName() const { return ModuleName; }
107   StringRef getObjFileName() const { return ObjFileName; }
108 
109   unsigned getModuleIndex() const { return Layout.Mod; }
110 
111   ArrayRef<std::string> source_files() const { return SourceFiles; }
112 
113   uint32_t calculateSerializedLength() const;
114 
115   /// Return the offset within the module symbol stream of the next symbol
116   /// record passed to addSymbol. Add four to account for the signature.
117   uint32_t getNextSymbolOffset() const { return SymbolByteSize + 4; }
118 
119   void finalize();
120   Error finalizeMsfLayout();
121 
122   /// Commit the DBI descriptor to the DBI stream.
123   Error commit(BinaryStreamWriter &ModiWriter);
124 
125   /// Commit the accumulated symbols to the module symbol stream. Safe to call
126   /// in parallel on different DbiModuleDescriptorBuilder objects. Only modifies
127   /// the pre-allocated stream in question.
128   Error commitSymbolStream(const msf::MSFLayout &MsfLayout,
129                            WritableBinaryStreamRef MsfBuffer);
130 
131 private:
132   uint32_t calculateC13DebugInfoSize() const;
133 
134   void addSourceFile(StringRef Path);
135   msf::MSFBuilder &MSF;
136 
137   uint32_t SymbolByteSize = 0;
138   uint32_t PdbFilePathNI = 0;
139   std::string ModuleName;
140   std::string ObjFileName;
141   std::vector<std::string> SourceFiles;
142   std::vector<SymbolListWrapper> Symbols;
143 
144   void *MergeSymsCtx = nullptr;
145   MergeSymbolsCallback MergeSymsCallback = nullptr;
146 
147   std::vector<StringTableFixup> StringTableFixups;
148 
149   std::vector<codeview::DebugSubsectionRecordBuilder> C13Builders;
150 
151   ModuleInfoHeader Layout;
152 };
153 
154 } // end namespace pdb
155 
156 } // end namespace llvm
157 
158 #endif // LLVM_DEBUGINFO_PDB_NATIVE_DBIMODULEDESCRIPTORBUILDER_H
159