[lld] r307979 - [PDB] Put LLD's PDB writing code in a class NFC

Reid Kleckner via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 13 17:14:58 PDT 2017


Author: rnk
Date: Thu Jul 13 17:14:58 2017
New Revision: 307979

URL: http://llvm.org/viewvc/llvm-project?rev=307979&view=rev
Log:
[PDB] Put LLD's PDB writing code in a class NFC

Summary:
We've accumulated about five or so data structures that are widely
referenced:
- PDBBuilder
- Type table
- Id table
- PDB string table
- Type server handler

I'm about to rewrite type server handling, and I need a new class in LLD
where I can put its state. By creating a new PDBLinker class, I hope to
put it there next.

Reviewers: ruiu

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D35392

Modified:
    lld/trunk/COFF/PDB.cpp

Modified: lld/trunk/COFF/PDB.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/PDB.cpp?rev=307979&r1=307978&r2=307979&view=diff
==============================================================================
--- lld/trunk/COFF/PDB.cpp (original)
+++ lld/trunk/COFF/PDB.cpp Thu Jul 13 17:14:58 2017
@@ -53,8 +53,65 @@ using llvm::object::coff_section;
 
 static ExitOnError ExitOnErr;
 
+namespace {
+class PDBLinker {
+public:
+  PDBLinker(SymbolTable *Symtab)
+      : Alloc(), Symtab(Symtab), Builder(Alloc), TypeTable(Alloc),
+        IDTable(Alloc) {}
+
+  /// Emit the basic PDB structure: initial streams, headers, etc.
+  void initialize(const llvm::codeview::DebugInfo *DI);
+
+  /// Link CodeView from each object file in the symbol table into the PDB.
+  void addObjectsToPDB();
+
+  /// Link CodeView from a single object file into the PDB.
+  void addObjectFile(ObjectFile *File);
+
+  /// Merge the type information from the .debug$T section in the given object
+  /// file. Produce a mapping from object file type indices to type or
+  /// item indices in the final PDB.
+  void mergeDebugT(ObjectFile *File, SmallVectorImpl<TypeIndex> &TypeIndexMap);
+
+  /// Add the section map and section contributions to the PDB.
+  void addSections(ArrayRef<uint8_t> SectionTable);
+
+  /// Write the PDB to disk.
+  void commit();
+
+private:
+  BumpPtrAllocator Alloc;
+
+  SymbolTable *Symtab;
+
+  pdb::PDBFileBuilder Builder;
+
+  /// Type records that will go into the PDB TPI stream.
+  TypeTableBuilder TypeTable;
+
+  /// Item records that will go into the PDB IPI stream.
+  TypeTableBuilder IDTable;
+
+  /// PDBs use a single global string table for filenames in the file checksum
+  /// table.
+  DebugStringTableSubsection PDBStrTab;
+
+  // Follow type servers.  If the same type server is encountered more than once
+  // for this instance of `PDBTypeServerHandler` (for example if many object
+  // files reference the same TypeServer), the types from the TypeServer will
+  // only be visited once.
+  pdb::PDBTypeServerHandler TSHandler;
+
+  llvm::SmallString<128> NativePath;
+
+  std::vector<pdb::SecMapEntry> SectionMap;
+};
+}
+
 // Returns a list of all SectionChunks.
-static void addSectionContribs(SymbolTable *Symtab, pdb::DbiStreamBuilder &DbiBuilder) {
+static void addSectionContribs(SymbolTable *Symtab,
+                               pdb::DbiStreamBuilder &DbiBuilder) {
   for (Chunk *C : Symtab->getChunks())
     if (auto *SC = dyn_cast<SectionChunk>(C))
       DbiBuilder.addSectionContrib(SC->File->ModuleDBI, SC->Header);
@@ -96,11 +153,8 @@ static void addTypeInfo(pdb::TpiStreamBu
   });
 }
 
-static void mergeDebugT(ObjectFile *File,
-                        TypeTableBuilder &IDTable,
-                        TypeTableBuilder &TypeTable,
-                        SmallVectorImpl<TypeIndex> &TypeIndexMap,
-                        pdb::PDBTypeServerHandler &Handler) {
+void PDBLinker::mergeDebugT(ObjectFile *File,
+                            SmallVectorImpl<TypeIndex> &TypeIndexMap) {
   ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$T");
   if (Data.empty())
     return;
@@ -109,7 +163,7 @@ static void mergeDebugT(ObjectFile *File
   // archive, look next to the archive path.
   StringRef LocalPath =
       !File->ParentName.empty() ? File->ParentName : File->getName();
-  Handler.addSearchPath(sys::path::parent_path(LocalPath));
+  TSHandler.addSearchPath(sys::path::parent_path(LocalPath));
 
   BinaryByteStream Stream(Data, support::little);
   CVTypeArray Types;
@@ -117,7 +171,7 @@ static void mergeDebugT(ObjectFile *File
   if (auto EC = Reader.readArray(Types, Reader.getLength()))
     fatal(EC, "Reader::readArray failed");
   if (auto Err = mergeTypeAndIdRecords(IDTable, TypeTable, TypeIndexMap,
-                                       &Handler, Types))
+                                       &TSHandler, Types))
     fatal(Err, "codeview::mergeTypeStreams failed");
 }
 
@@ -294,110 +348,105 @@ static ArrayRef<uint8_t> relocateDebugCh
                            ".debug$S");
 }
 
-// Add all object files to the PDB. Merge .debug$T sections into IpiData and
-// TpiData.
-static void addObjectsToPDB(BumpPtrAllocator &Alloc, SymbolTable *Symtab,
-                            pdb::PDBFileBuilder &Builder,
-                            TypeTableBuilder &TypeTable,
-                            TypeTableBuilder &IDTable) {
-  // Follow type servers.  If the same type server is encountered more than
-  // once for this instance of `PDBTypeServerHandler` (for example if many
-  // object files reference the same TypeServer), the types from the
-  // TypeServer will only be visited once.
-  pdb::PDBTypeServerHandler Handler;
-
-  // PDBs use a single global string table for filenames in the file checksum
-  // table.
-  auto PDBStrTab = std::make_shared<DebugStringTableSubsection>();
-
-  // Visit all .debug$T sections to add them to Builder.
-  for (ObjectFile *File : Symtab->ObjectFiles) {
-    // Add a module descriptor for every object file. We need to put an absolute
-    // path to the object into the PDB. If this is a plain object, we make its
-    // path absolute. If it's an object in an archive, we make the archive path
-    // absolute.
-    bool InArchive = !File->ParentName.empty();
-    SmallString<128> Path = InArchive ? File->ParentName : File->getName();
-    sys::fs::make_absolute(Path);
-    sys::path::native(Path, llvm::sys::path::Style::windows);
-    StringRef Name = InArchive ? File->getName() : StringRef(Path);
-
-    File->ModuleDBI = &ExitOnErr(Builder.getDbiBuilder().addModuleInfo(Name));
-    File->ModuleDBI->setObjFileName(Path);
-
-    // Before we can process symbol substreams from .debug$S, we need to process
-    // type information, file checksums, and the string table.  Add type info to
-    // the PDB first, so that we can get the map from object file type and item
-    // indices to PDB type and item indices.
-    SmallVector<TypeIndex, 128> TypeIndexMap;
-    mergeDebugT(File, IDTable, TypeTable, TypeIndexMap, Handler);
-
-    // Now do all line info.
-    for (SectionChunk *DebugChunk : File->getDebugChunks()) {
-      if (!DebugChunk->isLive() || DebugChunk->getSectionName() != ".debug$S")
-        continue;
+void PDBLinker::addObjectFile(ObjectFile *File) {
+  // Add a module descriptor for every object file. We need to put an absolute
+  // path to the object into the PDB. If this is a plain object, we make its
+  // path absolute. If it's an object in an archive, we make the archive path
+  // absolute.
+  bool InArchive = !File->ParentName.empty();
+  SmallString<128> Path = InArchive ? File->ParentName : File->getName();
+  sys::fs::make_absolute(Path);
+  sys::path::native(Path, sys::path::Style::windows);
+  StringRef Name = InArchive ? File->getName() : StringRef(Path);
+
+  File->ModuleDBI = &ExitOnErr(Builder.getDbiBuilder().addModuleInfo(Name));
+  File->ModuleDBI->setObjFileName(Path);
+
+  // Before we can process symbol substreams from .debug$S, we need to process
+  // type information, file checksums, and the string table.  Add type info to
+  // the PDB first, so that we can get the map from object file type and item
+  // indices to PDB type and item indices.
+  SmallVector<TypeIndex, 128> TypeIndexMap;
+  mergeDebugT(File, TypeIndexMap);
+
+  // Now do all live .debug$S sections.
+  for (SectionChunk *DebugChunk : File->getDebugChunks()) {
+    if (!DebugChunk->isLive() || DebugChunk->getSectionName() != ".debug$S")
+      continue;
 
-      ArrayRef<uint8_t> RelocatedDebugContents =
-          relocateDebugChunk(Alloc, DebugChunk);
-      if (RelocatedDebugContents.empty())
-        continue;
+    ArrayRef<uint8_t> RelocatedDebugContents =
+        relocateDebugChunk(Alloc, DebugChunk);
+    if (RelocatedDebugContents.empty())
+      continue;
 
-      DebugSubsectionArray Subsections;
-      BinaryStreamReader Reader(RelocatedDebugContents, support::little);
-      ExitOnErr(Reader.readArray(Subsections, RelocatedDebugContents.size()));
-
-      DebugStringTableSubsectionRef CVStrTab;
-      DebugChecksumsSubsectionRef Checksums;
-      for (const DebugSubsectionRecord &SS : Subsections) {
-        switch (SS.kind()) {
-        case DebugSubsectionKind::StringTable:
-          ExitOnErr(CVStrTab.initialize(SS.getRecordData()));
-          break;
-        case DebugSubsectionKind::FileChecksums:
-          ExitOnErr(Checksums.initialize(SS.getRecordData()));
-          break;
-        case DebugSubsectionKind::Lines:
-          // We can add the relocated line table directly to the PDB without
-          // modification because the file checksum offsets will stay the same.
-          File->ModuleDBI->addDebugSubsection(SS);
-          break;
-        case DebugSubsectionKind::Symbols:
-          mergeSymbolRecords(Alloc, File, TypeIndexMap, SS.getRecordData());
-          break;
-        default:
-          // FIXME: Process the rest of the subsections.
-          break;
-        }
+    DebugSubsectionArray Subsections;
+    BinaryStreamReader Reader(RelocatedDebugContents, support::little);
+    ExitOnErr(Reader.readArray(Subsections, RelocatedDebugContents.size()));
+
+    DebugStringTableSubsectionRef CVStrTab;
+    DebugChecksumsSubsectionRef Checksums;
+    for (const DebugSubsectionRecord &SS : Subsections) {
+      switch (SS.kind()) {
+      case DebugSubsectionKind::StringTable:
+        ExitOnErr(CVStrTab.initialize(SS.getRecordData()));
+        break;
+      case DebugSubsectionKind::FileChecksums:
+        ExitOnErr(Checksums.initialize(SS.getRecordData()));
+        break;
+      case DebugSubsectionKind::Lines:
+        // We can add the relocated line table directly to the PDB without
+        // modification because the file checksum offsets will stay the same.
+        File->ModuleDBI->addDebugSubsection(SS);
+        break;
+      case DebugSubsectionKind::Symbols:
+        mergeSymbolRecords(Alloc, File, TypeIndexMap, SS.getRecordData());
+        break;
+      default:
+        // FIXME: Process the rest of the subsections.
+        break;
       }
+    }
 
-      if (Checksums.valid()) {
-        // Make a new file checksum table that refers to offsets in the PDB-wide
-        // string table. Generally the string table subsection appears after the
-        // checksum table, so we have to do this after looping over all the
-        // subsections.
-        if (!CVStrTab.valid())
-          fatal(".debug$S sections must have both a string table subsection "
-                "and a checksum subsection table or neither");
-        auto NewChecksums =
-            make_unique<DebugChecksumsSubsection>(*PDBStrTab);
-        for (FileChecksumEntry &FC : Checksums) {
-          StringRef FileName = ExitOnErr(CVStrTab.getString(FC.FileNameOffset));
-          ExitOnErr(Builder.getDbiBuilder().addModuleSourceFile(
-              *File->ModuleDBI, FileName));
-          NewChecksums->addChecksum(FileName, FC.Kind, FC.Checksum);
-        }
-        File->ModuleDBI->addDebugSubsection(std::move(NewChecksums));
+    if (Checksums.valid()) {
+      // Make a new file checksum table that refers to offsets in the PDB-wide
+      // string table. Generally the string table subsection appears after the
+      // checksum table, so we have to do this after looping over all the
+      // subsections.
+      if (!CVStrTab.valid())
+        fatal(".debug$S sections must have both a string table subsection "
+              "and a checksum subsection table or neither");
+      auto NewChecksums = make_unique<DebugChecksumsSubsection>(PDBStrTab);
+      for (FileChecksumEntry &FC : Checksums) {
+        StringRef FileName = ExitOnErr(CVStrTab.getString(FC.FileNameOffset));
+        ExitOnErr(Builder.getDbiBuilder().addModuleSourceFile(*File->ModuleDBI,
+                                                              FileName));
+        NewChecksums->addChecksum(FileName, FC.Kind, FC.Checksum);
       }
+      File->ModuleDBI->addDebugSubsection(std::move(NewChecksums));
     }
   }
+}
+
+// Add all object files to the PDB. Merge .debug$T sections into IpiData and
+// TpiData.
+void PDBLinker::addObjectsToPDB() {
+  for (ObjectFile *File : Symtab->ObjectFiles)
+    addObjectFile(File);
 
-  Builder.getStringTableBuilder().setStrings(*PDBStrTab);
+  Builder.getStringTableBuilder().setStrings(PDBStrTab);
 
   // Construct TPI stream contents.
   addTypeInfo(Builder.getTpiBuilder(), TypeTable);
 
   // Construct IPI stream contents.
   addTypeInfo(Builder.getIpiBuilder(), IDTable);
+
+  // Add public and symbol records stream.
+
+  // For now we don't actually write any thing useful to the publics stream, but
+  // the act of "getting" it also creates it lazily so that we write an empty
+  // stream.
+  (void)Builder.getPublicsBuilder();
 }
 
 static void addLinkerModuleSymbols(StringRef Path,
@@ -428,7 +477,7 @@ static void addLinkerModuleSymbols(Strin
   std::string ArgStr = llvm::join(Args, " ");
   EBS.Fields.push_back("cwd");
   SmallString<64> cwd;
-  llvm::sys::fs::current_path(cwd);
+  sys::fs::current_path(cwd);
   EBS.Fields.push_back(cwd);
   EBS.Fields.push_back("exe");
   EBS.Fields.push_back(Config->Argv[0]);
@@ -447,8 +496,14 @@ static void addLinkerModuleSymbols(Strin
 // Creates a PDB file.
 void coff::createPDB(SymbolTable *Symtab, ArrayRef<uint8_t> SectionTable,
                      const llvm::codeview::DebugInfo *DI) {
-  BumpPtrAllocator Alloc;
-  pdb::PDBFileBuilder Builder(Alloc);
+  PDBLinker PDB(Symtab);
+  PDB.initialize(DI);
+  PDB.addObjectsToPDB();
+  PDB.addSections(SectionTable);
+  PDB.commit();
+}
+
+void PDBLinker::initialize(const llvm::codeview::DebugInfo *DI) {
   ExitOnErr(Builder.initialize(4096)); // 4096 is blocksize
 
   // Create streams in MSF for predefined streams, namely
@@ -460,11 +515,6 @@ void coff::createPDB(SymbolTable *Symtab
   auto &InfoBuilder = Builder.getInfoBuilder();
   InfoBuilder.setAge(DI ? DI->PDB70.Age : 0);
 
-  llvm::SmallString<128> NativePath(Config->PDBPath.begin(),
-                                    Config->PDBPath.end());
-  llvm::sys::fs::make_absolute(NativePath);
-  llvm::sys::path::native(NativePath, llvm::sys::path::Style::windows);
-
   pdb::PDB_UniqueId uuid{};
   if (DI)
     memcpy(&uuid, &DI->PDB70.Signature, sizeof(uuid));
@@ -476,32 +526,25 @@ void coff::createPDB(SymbolTable *Symtab
   pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder();
   DbiBuilder.setVersionHeader(pdb::PdbDbiV70);
   ExitOnErr(DbiBuilder.addDbgStream(pdb::DbgHeaderType::NewFPO, {}));
+}
 
-  // It's not entirely clear what this is, but the * Linker * module uses it.
-  uint32_t PdbFilePathNI = DbiBuilder.addECName(NativePath);
-
-  TypeTableBuilder TypeTable(BAlloc);
-  TypeTableBuilder IDTable(BAlloc);
-  addObjectsToPDB(Alloc, Symtab, Builder, TypeTable, IDTable);
-
-  // Add public and symbol records stream.
-
-  // For now we don't actually write any thing useful to the publics stream, but
-  // the act of "getting" it also creates it lazily so that we write an empty
-  // stream.
-  (void)Builder.getPublicsBuilder();
-
+void PDBLinker::addSections(ArrayRef<uint8_t> SectionTable) {
   // Add Section Contributions.
+  pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder();
   addSectionContribs(Symtab, DbiBuilder);
 
   // Add Section Map stream.
   ArrayRef<object::coff_section> Sections = {
       (const object::coff_section *)SectionTable.data(),
       SectionTable.size() / sizeof(object::coff_section)};
-  std::vector<pdb::SecMapEntry> SectionMap =
-      pdb::DbiStreamBuilder::createSectionMap(Sections);
+  SectionMap = pdb::DbiStreamBuilder::createSectionMap(Sections);
   DbiBuilder.setSectionMap(SectionMap);
 
+  // It's not entirely clear what this is, but the * Linker * module uses it.
+  NativePath = Config->PDBPath;
+  sys::fs::make_absolute(NativePath);
+  sys::path::native(NativePath, sys::path::Style::windows);
+  uint32_t PdbFilePathNI = DbiBuilder.addECName(NativePath);
   auto &LinkerModule = ExitOnErr(DbiBuilder.addModuleInfo("* Linker *"));
   LinkerModule.setPdbFilePathNI(PdbFilePathNI);
   addLinkerModuleSymbols(NativePath, LinkerModule, Alloc);
@@ -509,7 +552,9 @@ void coff::createPDB(SymbolTable *Symtab
   // Add COFF section header stream.
   ExitOnErr(
       DbiBuilder.addDbgStream(pdb::DbgHeaderType::SectionHdr, SectionTable));
+}
 
+void PDBLinker::commit() {
   // Write to a file.
   ExitOnErr(Builder.commit(Config->PDBPath));
 }




More information about the llvm-commits mailing list