[pdb] Write the module info and symbol record streams.

Previously we did not have support for writing detailed
module information for each module, as well as the symbol
records.  This patch adds support for this, and in doing
so enables the ability to construct minimal PDBs from
just a few lines of YAML.  A test is added to illustrate
this functionality.

llvm-svn: 297900
This commit is contained in:
Zachary Turner 2017-03-15 22:18:53 +00:00
parent 5545407fa4
commit ea4e60754e
18 changed files with 390 additions and 158 deletions

View File

@ -228,7 +228,7 @@ void coff::createPDB(StringRef Path, SymbolTable *Symtab,
pdb::DbiStreamBuilder::createSectionMap(Sections);
DbiBuilder.setSectionMap(SectionMap);
ExitOnErr(DbiBuilder.addModuleInfo("", "* Linker *"));
ExitOnErr(DbiBuilder.addModuleInfo("* Linker *"));
// Add COFF section header stream.
ExitOnErr(

View File

@ -31,11 +31,13 @@ struct coff_section;
namespace pdb {
class DbiStream;
struct DbiStreamHeader;
class ModInfoBuilder;
class PDBFile;
class DbiStreamBuilder {
public:
DbiStreamBuilder(msf::MSFBuilder &Msf);
~DbiStreamBuilder();
DbiStreamBuilder(const DbiStreamBuilder &) = delete;
DbiStreamBuilder &operator=(const DbiStreamBuilder &) = delete;
@ -55,12 +57,12 @@ public:
uint32_t calculateSerializedLength() const;
Error addModuleInfo(StringRef ObjFile, StringRef Module);
Expected<ModInfoBuilder &> addModuleInfo(StringRef ModuleName);
Error addModuleSourceFile(StringRef Module, StringRef File);
Error finalizeMsfLayout();
Error commit(const msf::MSFLayout &Layout, WritableBinaryStreamRef Buffer);
Error commit(const msf::MSFLayout &Layout, WritableBinaryStreamRef MsfBuffer);
// A helper function to create Section Contributions from COFF input
// section headers.
@ -88,12 +90,6 @@ private:
Error generateModiSubstream();
Error generateFileInfoSubstream();
struct ModuleInfo {
std::vector<StringRef> SourceFiles;
StringRef Obj;
StringRef Mod;
};
msf::MSFBuilder &Msf;
BumpPtrAllocator &Allocator;
@ -107,13 +103,12 @@ private:
const DbiStreamHeader *Header;
StringMap<std::unique_ptr<ModuleInfo>> ModuleInfos;
std::vector<ModuleInfo *> ModuleInfoList;
StringMap<std::unique_ptr<ModInfoBuilder>> ModiMap;
std::vector<ModInfoBuilder *> ModiList;
StringMap<uint32_t> SourceFileNames;
WritableBinaryStreamRef NamesBuffer;
MutableBinaryByteStream ModInfoBuffer;
MutableBinaryByteStream FileInfoBuffer;
ArrayRef<SectionContrib> SectionContribs;
ArrayRef<SecMapEntry> SectionMap;

View File

@ -0,0 +1,74 @@
//===- ModInfoBuilder.h - PDB module information ----------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEBUGINFO_PDB_RAW_MODINFOBUILDER_H
#define LLVM_DEBUGINFO_PDB_RAW_MODINFOBUILDER_H
#include "llvm/ADT/StringRef.h"
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
#include "llvm/Support/Error.h"
#include <cstdint>
#include <string>
#include <vector>
namespace llvm {
class BinaryStreamWriter;
namespace msf {
class MSFBuilder;
struct MSFLayout;
}
namespace pdb {
class ModInfoBuilder {
friend class DbiStreamBuilder;
public:
ModInfoBuilder(StringRef ModuleName, uint32_t ModIndex, msf::MSFBuilder &Msf);
ModInfoBuilder(const ModInfoBuilder &) = delete;
ModInfoBuilder &operator=(const ModInfoBuilder &) = delete;
void setObjFileName(StringRef Name);
void addSymbol(codeview::CVSymbol Symbol);
uint16_t getStreamIndex() const;
StringRef getModuleName() const { return ModuleName; }
StringRef getObjFileName() const { return ObjFileName; }
ArrayRef<std::string> source_files() const {
return makeArrayRef(SourceFiles);
}
uint32_t calculateSerializedLength() const;
void finalize();
Error finalizeMsfLayout();
Error commit(BinaryStreamWriter &ModiWriter, const msf::MSFLayout &MsfLayout,
WritableBinaryStreamRef MsfBuffer);
private:
void addSourceFile(StringRef Path);
msf::MSFBuilder &MSF;
uint32_t SymbolByteSize = 0;
std::string ModuleName;
std::string ObjFileName;
std::vector<std::string> SourceFiles;
std::vector<codeview::CVSymbol> Symbols;
ModuleInfoHeader Layout;
};
} // end namespace pdb
} // end namespace llvm
#endif // LLVM_DEBUGINFO_PDB_RAW_MODINFOBUILDER_H

View File

@ -28,6 +28,7 @@ enum class raw_error_code {
duplicate_entry,
no_entry,
not_writable,
stream_too_long,
invalid_tpi_hash,
};

View File

@ -154,6 +154,7 @@ public:
uint32_t getOffset() const { return Offset; }
uint32_t getLength() const { return Stream.getLength(); }
uint32_t bytesRemaining() const { return getLength() - getOffset(); }
Error padToAlignment(uint32_t Align);
protected:
WritableBinaryStreamRef Stream;

View File

@ -38,6 +38,7 @@ add_pdb_impl_folder(Native
Native/InfoStream.cpp
Native/InfoStreamBuilder.cpp
Native/ModInfo.cpp
Native/ModInfoBuilder.cpp
Native/ModStream.cpp
Native/NativeCompilandSymbol.cpp
Native/NativeEnumModules.cpp

View File

@ -13,6 +13,7 @@
#include "llvm/DebugInfo/MSF/MSFBuilder.h"
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
#include "llvm/DebugInfo/PDB/Native/ModInfoBuilder.h"
#include "llvm/DebugInfo/PDB/Native/RawError.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/BinaryStreamWriter.h"
@ -23,15 +24,13 @@ using namespace llvm::codeview;
using namespace llvm::msf;
using namespace llvm::pdb;
namespace {
class ModiSubstreamBuilder {};
}
DbiStreamBuilder::DbiStreamBuilder(msf::MSFBuilder &Msf)
: Msf(Msf), Allocator(Msf.getAllocator()), Age(1), BuildNumber(0),
PdbDllVersion(0), PdbDllRbld(0), Flags(0), MachineType(PDB_Machine::x86),
Header(nullptr), DbgStreams((int)DbgHeaderType::Max) {}
DbiStreamBuilder::~DbiStreamBuilder() {}
void DbiStreamBuilder::setVersionHeader(PdbRaw_DbiVer V) { VerHeader = V; }
void DbiStreamBuilder::setAge(uint32_t A) { Age = A; }
@ -75,39 +74,37 @@ uint32_t DbiStreamBuilder::calculateSerializedLength() const {
calculateSectionMapStreamSize() + calculateDbgStreamsSize();
}
Error DbiStreamBuilder::addModuleInfo(StringRef ObjFile, StringRef Module) {
auto Entry = llvm::make_unique<ModuleInfo>();
ModuleInfo *M = Entry.get();
Entry->Mod = Module;
Entry->Obj = ObjFile;
auto Result = ModuleInfos.insert(std::make_pair(Module, std::move(Entry)));
Expected<ModInfoBuilder &>
DbiStreamBuilder::addModuleInfo(StringRef ModuleName) {
uint32_t Index = ModiList.size();
auto MIB = llvm::make_unique<ModInfoBuilder>(ModuleName, Index, Msf);
auto M = MIB.get();
auto Result = ModiMap.insert(std::make_pair(ModuleName, std::move(MIB)));
if (!Result.second)
return make_error<RawError>(raw_error_code::duplicate_entry,
"The specified module already exists");
ModuleInfoList.push_back(M);
return Error::success();
ModiList.push_back(M);
return *M;
}
Error DbiStreamBuilder::addModuleSourceFile(StringRef Module, StringRef File) {
auto ModIter = ModuleInfos.find(Module);
if (ModIter == ModuleInfos.end())
auto ModIter = ModiMap.find(Module);
if (ModIter == ModiMap.end())
return make_error<RawError>(raw_error_code::no_entry,
"The specified module was not found");
uint32_t Index = SourceFileNames.size();
SourceFileNames.insert(std::make_pair(File, Index));
auto &ModEntry = *ModIter;
ModEntry.second->SourceFiles.push_back(File);
ModEntry.second->addSourceFile(File);
return Error::success();
}
uint32_t DbiStreamBuilder::calculateModiSubstreamSize() const {
uint32_t Size = 0;
for (const auto &M : ModuleInfoList) {
Size += sizeof(ModuleInfoHeader);
Size += M->Mod.size() + 1;
Size += M->Obj.size() + 1;
}
return alignTo(Size, sizeof(uint32_t));
for (const auto &M : ModiList)
Size += M->calculateSerializedLength();
return Size;
}
uint32_t DbiStreamBuilder::calculateSectionContribsStreamSize() const {
@ -127,11 +124,11 @@ uint32_t DbiStreamBuilder::calculateFileInfoSubstreamSize() const {
uint32_t Size = 0;
Size += sizeof(ulittle16_t); // NumModules
Size += sizeof(ulittle16_t); // NumSourceFiles
Size += ModuleInfoList.size() * sizeof(ulittle16_t); // ModIndices
Size += ModuleInfoList.size() * sizeof(ulittle16_t); // ModFileCounts
Size += ModiList.size() * sizeof(ulittle16_t); // ModIndices
Size += ModiList.size() * sizeof(ulittle16_t); // ModFileCounts
uint32_t NumFileInfos = 0;
for (const auto &M : ModuleInfoList)
NumFileInfos += M->SourceFiles.size();
for (const auto &M : ModiList)
NumFileInfos += M->source_files().size();
Size += NumFileInfos * sizeof(ulittle32_t); // FileNameOffsets
Size += calculateNamesBufferSize();
return alignTo(Size, sizeof(uint32_t));
@ -149,31 +146,6 @@ uint32_t DbiStreamBuilder::calculateDbgStreamsSize() const {
return DbgStreams.size() * sizeof(uint16_t);
}
Error DbiStreamBuilder::generateModiSubstream() {
uint32_t Size = calculateModiSubstreamSize();
auto Data = Allocator.Allocate<uint8_t>(Size);
ModInfoBuffer = MutableBinaryByteStream(MutableArrayRef<uint8_t>(Data, Size),
llvm::support::little);
BinaryStreamWriter ModiWriter(ModInfoBuffer);
for (const auto &M : ModuleInfoList) {
ModuleInfoHeader Layout = {};
Layout.ModDiStream = kInvalidStreamIndex;
Layout.NumFiles = M->SourceFiles.size();
if (auto EC = ModiWriter.writeObject(Layout))
return EC;
if (auto EC = ModiWriter.writeCString(M->Mod))
return EC;
if (auto EC = ModiWriter.writeCString(M->Obj))
return EC;
}
if (ModiWriter.bytesRemaining() > sizeof(uint32_t))
return make_error<RawError>(raw_error_code::invalid_format,
"Unexpected bytes in Modi Stream Data");
return Error::success();
}
Error DbiStreamBuilder::generateFileInfoSubstream() {
uint32_t Size = calculateFileInfoSubstreamSize();
uint32_t NameSize = calculateNamesBufferSize();
@ -187,7 +159,7 @@ Error DbiStreamBuilder::generateFileInfoSubstream() {
WritableBinaryStreamRef(FileInfoBuffer).keep_front(NamesOffset);
BinaryStreamWriter MetadataWriter(MetadataBuffer);
uint16_t ModiCount = std::min<uint32_t>(UINT16_MAX, ModuleInfos.size());
uint16_t ModiCount = std::min<uint32_t>(UINT16_MAX, ModiList.size());
uint16_t FileCount = std::min<uint32_t>(UINT16_MAX, SourceFileNames.size());
if (auto EC = MetadataWriter.writeInteger(ModiCount)) // NumModules
return EC;
@ -197,8 +169,8 @@ Error DbiStreamBuilder::generateFileInfoSubstream() {
if (auto EC = MetadataWriter.writeInteger(I)) // Mod Indices
return EC;
}
for (const auto MI : ModuleInfoList) {
FileCount = static_cast<uint16_t>(MI->SourceFiles.size());
for (const auto &MI : ModiList) {
FileCount = static_cast<uint16_t>(MI->source_files().size());
if (auto EC = MetadataWriter.writeInteger(FileCount)) // Mod File Counts
return EC;
}
@ -215,8 +187,8 @@ Error DbiStreamBuilder::generateFileInfoSubstream() {
return EC;
}
for (const auto MI : ModuleInfoList) {
for (StringRef Name : MI->SourceFiles) {
for (const auto &MI : ModiList) {
for (StringRef Name : MI->source_files()) {
auto Result = SourceFileNames.find(Name);
if (Result == SourceFileNames.end())
return make_error<RawError>(raw_error_code::no_entry,
@ -242,13 +214,13 @@ Error DbiStreamBuilder::finalize() {
if (Header)
return Error::success();
DbiStreamHeader *H = Allocator.Allocate<DbiStreamHeader>();
for (auto &MI : ModiList)
MI->finalize();
if (auto EC = generateModiSubstream())
return EC;
if (auto EC = generateFileInfoSubstream())
return EC;
DbiStreamHeader *H = Allocator.Allocate<DbiStreamHeader>();
H->VersionHeader = *VerHeader;
H->VersionSignature = -1;
H->Age = Age;
@ -260,7 +232,7 @@ Error DbiStreamBuilder::finalize() {
H->ECSubstreamSize = 0;
H->FileInfoSize = FileInfoBuffer.getLength();
H->ModiSubstreamSize = ModInfoBuffer.getLength();
H->ModiSubstreamSize = calculateModiSubstreamSize();
H->OptionalDbgHdrSize = DbgStreams.size() * sizeof(uint16_t);
H->SecContrSubstreamSize = calculateSectionContribsStreamSize();
H->SectionMapSize = calculateSectionMapStreamSize();
@ -275,6 +247,11 @@ Error DbiStreamBuilder::finalize() {
}
Error DbiStreamBuilder::finalizeMsfLayout() {
for (auto &MI : ModiList) {
if (auto EC = MI->finalizeMsfLayout())
return EC;
}
uint32_t Length = calculateSerializedLength();
if (auto EC = Msf.setStreamSize(StreamDBI, Length))
return EC;
@ -360,19 +337,21 @@ std::vector<SecMapEntry> DbiStreamBuilder::createSectionMap(
}
Error DbiStreamBuilder::commit(const msf::MSFLayout &Layout,
WritableBinaryStreamRef Buffer) {
WritableBinaryStreamRef MsfBuffer) {
if (auto EC = finalize())
return EC;
auto InfoS =
WritableMappedBlockStream::createIndexedStream(Layout, Buffer, StreamDBI);
auto DbiS = WritableMappedBlockStream::createIndexedStream(Layout, MsfBuffer,
StreamDBI);
BinaryStreamWriter Writer(*InfoS);
BinaryStreamWriter Writer(*DbiS);
if (auto EC = Writer.writeObject(*Header))
return EC;
if (auto EC = Writer.writeStreamRef(ModInfoBuffer))
return EC;
for (auto &M : ModiList) {
if (auto EC = M->commit(Writer, Layout, MsfBuffer))
return EC;
}
if (!SectionContribs.empty()) {
if (auto EC = Writer.writeEnum(DbiSecContribVer60))
@ -401,7 +380,7 @@ Error DbiStreamBuilder::commit(const msf::MSFLayout &Layout,
if (Stream.StreamNumber == kInvalidStreamIndex)
continue;
auto WritableStream = WritableMappedBlockStream::createIndexedStream(
Layout, Buffer, Stream.StreamNumber);
Layout, MsfBuffer, Stream.StreamNumber);
BinaryStreamWriter DbgStreamWriter(*WritableStream);
if (auto EC = DbgStreamWriter.writeArray(Stream.Data))
return EC;

View File

@ -0,0 +1,136 @@
//===- ModInfoBuilder.cpp - PDB Module Info Stream Creation -----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/PDB/Native/ModInfoBuilder.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/DebugInfo/MSF/MSFBuilder.h"
#include "llvm/DebugInfo/MSF/MSFCommon.h"
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
#include "llvm/DebugInfo/PDB/Native/ModInfo.h"
#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
#include "llvm/DebugInfo/PDB/Native/RawError.h"
#include "llvm/Support/BinaryItemStream.h"
#include "llvm/Support/BinaryStreamWriter.h"
#include "llvm/Support/COFF.h"
using namespace llvm;
using namespace llvm::codeview;
using namespace llvm::msf;
using namespace llvm::pdb;
namespace llvm {
template <> struct BinaryItemTraits<CVSymbol> {
static size_t length(const CVSymbol &Item) { return Item.RecordData.size(); }
static ArrayRef<uint8_t> bytes(const CVSymbol &Item) {
return Item.RecordData;
}
};
}
static uint32_t calculateDiSymbolStreamSize(uint32_t SymbolByteSize) {
uint32_t Size = sizeof(uint32_t); // Signature
Size += SymbolByteSize; // Symbol Data
Size += 0; // TODO: Layout.LineBytes
Size += 0; // TODO: Layout.C13Bytes
Size += sizeof(uint32_t); // GlobalRefs substream size (always 0)
Size += 0; // GlobalRefs substream bytes
return Size;
}
ModInfoBuilder::ModInfoBuilder(StringRef ModuleName, uint32_t ModIndex,
msf::MSFBuilder &Msf)
: MSF(Msf), ModuleName(ModuleName) {
Layout.Mod = ModIndex;
}
uint16_t ModInfoBuilder::getStreamIndex() const { return Layout.ModDiStream; }
void ModInfoBuilder::setObjFileName(StringRef Name) { ObjFileName = Name; }
void ModInfoBuilder::addSymbol(CVSymbol Symbol) {
Symbols.push_back(Symbol);
SymbolByteSize += Symbol.data().size();
}
void ModInfoBuilder::addSourceFile(StringRef Path) {
SourceFiles.push_back(Path);
}
uint32_t ModInfoBuilder::calculateSerializedLength() const {
uint32_t L = sizeof(Layout);
uint32_t M = ModuleName.size() + 1;
uint32_t O = ObjFileName.size() + 1;
return alignTo(L + M + O, sizeof(uint32_t));
}
void ModInfoBuilder::finalize() {
Layout.C13Bytes = 0;
Layout.FileNameOffs = 0; // TODO: Fix this
Layout.Flags = 0; // TODO: Fix this
Layout.LineBytes = 0;
(void)Layout.Mod; // Set in constructor
(void)Layout.ModDiStream; // Set in finalizeMsfLayout
Layout.NumFiles = SourceFiles.size();
Layout.PdbFilePathNI = 0;
Layout.SrcFileNameNI = 0;
// This value includes both the signature field as well as the record bytes
// from the symbol stream.
Layout.SymBytes = SymbolByteSize + sizeof(uint32_t);
}
Error ModInfoBuilder::finalizeMsfLayout() {
this->Layout.ModDiStream = kInvalidStreamIndex;
auto ExpectedSN = MSF.addStream(calculateDiSymbolStreamSize(SymbolByteSize));
if (!ExpectedSN)
return ExpectedSN.takeError();
Layout.ModDiStream = *ExpectedSN;
return Error::success();
}
Error ModInfoBuilder::commit(BinaryStreamWriter &ModiWriter,
const msf::MSFLayout &MsfLayout,
WritableBinaryStreamRef MsfBuffer) {
// We write the Modi record to the `ModiWriter`, but we additionally write its
// symbol stream to a brand new stream.
if (auto EC = ModiWriter.writeObject(Layout))
return EC;
if (auto EC = ModiWriter.writeCString(ModuleName))
return EC;
if (auto EC = ModiWriter.writeCString(ObjFileName))
return EC;
if (auto EC = ModiWriter.padToAlignment(sizeof(uint32_t)))
return EC;
if (Layout.ModDiStream != kInvalidStreamIndex) {
auto NS = WritableMappedBlockStream::createIndexedStream(
MsfLayout, MsfBuffer, Layout.ModDiStream);
WritableBinaryStreamRef Ref(*NS);
BinaryStreamWriter SymbolWriter(Ref);
// Write the symbols.
if (auto EC =
SymbolWriter.writeInteger<uint32_t>(COFF::DEBUG_SECTION_MAGIC))
return EC;
BinaryItemStream<CVSymbol> Records(llvm::support::endianness::little);
Records.setItems(Symbols);
BinaryStreamRef RecordsRef(Records);
if (auto EC = SymbolWriter.writeStreamRef(RecordsRef))
return EC;
// TODO: Write C11 Line data
// TODO: Write C13 Line data
// TODO: Figure out what GlobalRefs substream actually is and populate it.
if (auto EC = SymbolWriter.writeInteger<uint32_t>(0))
return EC;
if (SymbolWriter.bytesRemaining() > 0)
return make_error<RawError>(raw_error_code::stream_too_long);
}
return Error::success();
}

View File

@ -38,6 +38,8 @@ public:
return "The entry does not exist.";
case raw_error_code::not_writable:
return "The PDB does not support writing.";
case raw_error_code::stream_too_long:
return "The stream was longer than expected.";
case raw_error_code::invalid_tpi_hash:
return "The Type record has an invalid hash value.";
}

View File

@ -9,6 +9,7 @@
#include "llvm/Support/BinaryStreamWriter.h"
#include "llvm/Support/BinaryStreamError.h"
#include "llvm/Support/BinaryStreamReader.h"
#include "llvm/Support/BinaryStreamRef.h"
@ -57,3 +58,11 @@ Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref, uint32_t Length) {
}
return Error::success();
}
Error BinaryStreamWriter::padToAlignment(uint32_t Align) {
uint32_t NewOffset = alignTo(Offset, Align);
if (NewOffset > getLength())
return make_error<BinaryStreamError>(stream_error_code::stream_too_short);
Offset = NewOffset;
return Error::success();
}

View File

@ -0,0 +1,11 @@
---
DbiStream:
Modules:
- Module: one-symbol.yaml
Modi:
Records:
- Kind: S_OBJNAME
ObjNameSym:
Signature: 0
ObjectName: 'c:\foo\one-symbol.yaml'
...

View File

@ -0,0 +1,11 @@
; This testcase verifies that we can produce a minimal PDB, while
; serving as an example for how to construct a minimal PDB for other
; testcases. It takes as input a small fragment of hand-written yaml
; that specifies nothing about the PDB other than a definition of one
; symbol that it contains. Then it produces a PDB, and uses the
; resulting PDB to go back to yaml, and verify that the resulting yaml
; is identical.
; RUN: llvm-pdbdump yaml2pdb -pdb=%t.pdb %p/Inputs/one-symbol.yaml
; RUN: llvm-pdbdump pdb2yaml -minimal -dbi-module-syms -no-file-headers %t.pdb > %t.pdb.yaml
; RUN: diff -b %p/Inputs/one-symbol.yaml %t.pdb.yaml

View File

@ -4,18 +4,14 @@
YAML: ---
YAML: MSF:
YAML: SuperBlock:
YAML: BlockSize: 4096
YAML: FreeBlockMap: 2
YAML: NumBlocks: 25
YAML: NumDirectoryBytes: 136
YAML: Unknown1: 0
YAML: BlockMapAddr: 24
YAML: NumDirectoryBlocks: 1
YAML: DirectoryBlocks: [ 23 ]
YAML: NumStreams: 0
YAML: FileSize: 102400
YAML: TpiStream:
YAML: Version: VC80
YAML: Records:
YAML: - Kind: LF_ARGLIST
YAML: ArgList:

View File

@ -158,11 +158,11 @@ void MappingTraits<PdbObject>::mapping(IO &IO, PdbObject &Obj) {
}
void MappingTraits<MSFHeaders>::mapping(IO &IO, MSFHeaders &Obj) {
IO.mapRequired("SuperBlock", Obj.SuperBlock);
IO.mapRequired("NumDirectoryBlocks", Obj.NumDirectoryBlocks);
IO.mapRequired("DirectoryBlocks", Obj.DirectoryBlocks);
IO.mapRequired("NumStreams", Obj.NumStreams);
IO.mapRequired("FileSize", Obj.FileSize);
IO.mapOptional("SuperBlock", Obj.SuperBlock);
IO.mapOptional("NumDirectoryBlocks", Obj.NumDirectoryBlocks);
IO.mapOptional("DirectoryBlocks", Obj.DirectoryBlocks);
IO.mapOptional("NumStreams", Obj.NumStreams);
IO.mapOptional("FileSize", Obj.FileSize);
}
void MappingTraits<msf::SuperBlock>::mapping(IO &IO, msf::SuperBlock &SB) {
@ -170,12 +170,13 @@ void MappingTraits<msf::SuperBlock>::mapping(IO &IO, msf::SuperBlock &SB) {
::memcpy(SB.MagicBytes, msf::Magic, sizeof(msf::Magic));
}
IO.mapRequired("BlockSize", SB.BlockSize);
IO.mapRequired("FreeBlockMap", SB.FreeBlockMapBlock);
IO.mapRequired("NumBlocks", SB.NumBlocks);
IO.mapRequired("NumDirectoryBytes", SB.NumDirectoryBytes);
IO.mapRequired("Unknown1", SB.Unknown1);
IO.mapRequired("BlockMapAddr", SB.BlockMapAddr);
using u32 = support::ulittle32_t;
IO.mapOptional("BlockSize", SB.BlockSize, u32(4096U));
IO.mapOptional("FreeBlockMap", SB.FreeBlockMapBlock, u32(0U));
IO.mapOptional("NumBlocks", SB.NumBlocks, u32(0U));
IO.mapOptional("NumDirectoryBytes", SB.NumDirectoryBytes, u32(0U));
IO.mapOptional("Unknown1", SB.Unknown1, u32(0U));
IO.mapOptional("BlockMapAddr", SB.BlockMapAddr, u32(0U));
}
void MappingTraits<StreamBlockList>::mapping(IO &IO, StreamBlockList &SB) {
@ -183,26 +184,26 @@ void MappingTraits<StreamBlockList>::mapping(IO &IO, StreamBlockList &SB) {
}
void MappingTraits<PdbInfoStream>::mapping(IO &IO, PdbInfoStream &Obj) {
IO.mapRequired("Age", Obj.Age);
IO.mapRequired("Guid", Obj.Guid);
IO.mapRequired("Signature", Obj.Signature);
IO.mapRequired("Version", Obj.Version);
IO.mapOptional("Age", Obj.Age, 1U);
IO.mapOptional("Guid", Obj.Guid);
IO.mapOptional("Signature", Obj.Signature, 0U);
IO.mapOptional("Version", Obj.Version, PdbImplVC70);
}
void MappingContextTraits<PdbDbiStream, pdb::yaml::SerializationContext>::mapping(IO &IO, PdbDbiStream &Obj, pdb::yaml::SerializationContext &Context) {
IO.mapRequired("VerHeader", Obj.VerHeader);
IO.mapRequired("Age", Obj.Age);
IO.mapRequired("BuildNumber", Obj.BuildNumber);
IO.mapRequired("PdbDllVersion", Obj.PdbDllVersion);
IO.mapRequired("PdbDllRbld", Obj.PdbDllRbld);
IO.mapRequired("Flags", Obj.Flags);
IO.mapRequired("MachineType", Obj.MachineType);
IO.mapOptional("VerHeader", Obj.VerHeader, PdbDbiV70);
IO.mapOptional("Age", Obj.Age, 1U);
IO.mapOptional("BuildNumber", Obj.BuildNumber, uint16_t(0U));
IO.mapOptional("PdbDllVersion", Obj.PdbDllVersion, 0U);
IO.mapOptional("PdbDllRbld", Obj.PdbDllRbld, uint16_t(0U));
IO.mapOptional("Flags", Obj.Flags, uint16_t(1U));
IO.mapOptional("MachineType", Obj.MachineType, PDB_Machine::x86);
IO.mapOptionalWithContext("Modules", Obj.ModInfos, Context);
}
void MappingContextTraits<PdbTpiStream, pdb::yaml::SerializationContext>::mapping(
IO &IO, pdb::yaml::PdbTpiStream &Obj, pdb::yaml::SerializationContext &Context) {
IO.mapRequired("Version", Obj.Version);
IO.mapOptional("Version", Obj.Version, PdbTpiV80);
IO.mapRequired("Records", Obj.Records, Context);
}
@ -234,13 +235,13 @@ void MappingContextTraits<PdbSymbolRecord, pdb::yaml::SerializationContext>::map
}
void MappingContextTraits<PdbModiStream, pdb::yaml::SerializationContext>::mapping(IO &IO, PdbModiStream &Obj, pdb::yaml::SerializationContext &Context) {
IO.mapRequired("Signature", Obj.Signature);
IO.mapOptional("Signature", Obj.Signature, 4U);
IO.mapRequired("Records", Obj.Symbols, Context);
}
void MappingContextTraits<PdbDbiModuleInfo, pdb::yaml::SerializationContext>::mapping(IO &IO, PdbDbiModuleInfo &Obj, pdb::yaml::SerializationContext &Context) {
IO.mapRequired("Module", Obj.Mod);
IO.mapRequired("ObjFile", Obj.Obj);
IO.mapOptional("ObjFile", Obj.Obj, Obj.Mod);
IO.mapOptional("SourceFiles", Obj.SourceFiles);
IO.mapOptionalWithContext("Modi", Obj.Modi, Context);
}

View File

@ -32,10 +32,10 @@ struct SerializationContext;
struct MSFHeaders {
msf::SuperBlock SuperBlock;
uint32_t NumDirectoryBlocks;
uint32_t NumDirectoryBlocks = 0;
std::vector<uint32_t> DirectoryBlocks;
uint32_t NumStreams;
uint32_t FileSize;
uint32_t NumStreams = 0;
uint32_t FileSize = 0;
};
struct StreamBlockList {
@ -48,9 +48,9 @@ struct NamedStreamMapping {
};
struct PdbInfoStream {
PdbRaw_ImplVer Version;
uint32_t Signature;
uint32_t Age;
PdbRaw_ImplVer Version = PdbImplVC70;
uint32_t Signature = 0;
uint32_t Age = 1;
PDB_UniqueId Guid;
std::vector<NamedStreamMapping> NamedStreams;
};
@ -72,13 +72,13 @@ struct PdbDbiModuleInfo {
};
struct PdbDbiStream {
PdbRaw_DbiVer VerHeader;
uint32_t Age;
uint16_t BuildNumber;
uint32_t PdbDllVersion;
uint16_t PdbDllRbld;
uint16_t Flags;
PDB_Machine MachineType;
PdbRaw_DbiVer VerHeader = PdbDbiV70;
uint32_t Age = 1;
uint16_t BuildNumber = 0;
uint32_t PdbDllVersion = 0;
uint16_t PdbDllRbld = 0;
uint16_t Flags = 1;
PDB_Machine MachineType = PDB_Machine::x86;
std::vector<PdbDbiModuleInfo> ModInfos;
};
@ -92,7 +92,7 @@ struct PdbTpiFieldListRecord {
};
struct PdbTpiStream {
PdbRaw_TpiVer Version;
PdbRaw_TpiVer Version = PdbTpiV80;
std::vector<PdbTpiRecord> Records;
};

View File

@ -24,7 +24,9 @@ using namespace llvm;
using namespace llvm::pdb;
YAMLOutputStyle::YAMLOutputStyle(PDBFile &File)
: File(File), Out(outs()), Obj(File.getAllocator()) {}
: File(File), Out(outs()), Obj(File.getAllocator()) {
Out.setWriteDefaultValues(!opts::pdb2yaml::Minimal);
}
Error YAMLOutputStyle::dump() {
if (opts::pdb2yaml::StreamDirectory)

View File

@ -39,6 +39,7 @@
#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h"
#include "llvm/DebugInfo/PDB/Native/ModInfoBuilder.h"
#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h"
@ -293,6 +294,9 @@ cl::opt<bool>
cl::desc("Do not dump MSF file headers (you will not be able "
"to generate a fresh PDB from the resulting YAML)"),
cl::sub(PdbToYamlSubcommand), cl::init(false));
cl::opt<bool> Minimal("minimal",
cl::desc("Don't write fields with default values"),
cl::sub(PdbToYamlSubcommand), cl::init(false));
cl::opt<bool> StreamMetadata(
"stream-metadata",
@ -367,13 +371,13 @@ static void yamlToPdb(StringRef Path) {
llvm::yaml::Input In(Buffer->getBuffer());
pdb::yaml::PdbObject YamlObj(Allocator);
In >> YamlObj;
if (!YamlObj.Headers.hasValue())
ExitOnErr(make_error<GenericError>(generic_error_code::unspecified,
"Yaml does not contain MSF headers"));
PDBFileBuilder Builder(Allocator);
ExitOnErr(Builder.initialize(YamlObj.Headers->SuperBlock.BlockSize));
uint32_t BlockSize = 4096;
if (YamlObj.Headers.hasValue())
BlockSize = YamlObj.Headers->SuperBlock.BlockSize;
ExitOnErr(Builder.initialize(BlockSize));
// Add each of the reserved streams. We ignore stream metadata in the
// yaml, because we will reconstruct our own view of the streams. For
// example, the YAML may say that there were 20 streams in the original
@ -389,43 +393,51 @@ static void yamlToPdb(StringRef Path) {
Strings.insert(S);
}
if (YamlObj.PdbStream.hasValue()) {
auto &InfoBuilder = Builder.getInfoBuilder();
InfoBuilder.setAge(YamlObj.PdbStream->Age);
InfoBuilder.setGuid(YamlObj.PdbStream->Guid);
InfoBuilder.setSignature(YamlObj.PdbStream->Signature);
InfoBuilder.setVersion(YamlObj.PdbStream->Version);
}
pdb::yaml::PdbInfoStream DefaultInfoStream;
pdb::yaml::PdbDbiStream DefaultDbiStream;
pdb::yaml::PdbTpiStream DefaultTpiStream;
if (YamlObj.DbiStream.hasValue()) {
auto &DbiBuilder = Builder.getDbiBuilder();
DbiBuilder.setAge(YamlObj.DbiStream->Age);
DbiBuilder.setBuildNumber(YamlObj.DbiStream->BuildNumber);
DbiBuilder.setFlags(YamlObj.DbiStream->Flags);
DbiBuilder.setMachineType(YamlObj.DbiStream->MachineType);
DbiBuilder.setPdbDllRbld(YamlObj.DbiStream->PdbDllRbld);
DbiBuilder.setPdbDllVersion(YamlObj.DbiStream->PdbDllVersion);
DbiBuilder.setVersionHeader(YamlObj.DbiStream->VerHeader);
for (const auto &MI : YamlObj.DbiStream->ModInfos) {
ExitOnErr(DbiBuilder.addModuleInfo(MI.Obj, MI.Mod));
for (auto S : MI.SourceFiles)
ExitOnErr(DbiBuilder.addModuleSourceFile(MI.Mod, S));
const auto &Info = YamlObj.PdbStream.getValueOr(DefaultInfoStream);
auto &InfoBuilder = Builder.getInfoBuilder();
InfoBuilder.setAge(Info.Age);
InfoBuilder.setGuid(Info.Guid);
InfoBuilder.setSignature(Info.Signature);
InfoBuilder.setVersion(Info.Version);
const auto &Dbi = YamlObj.DbiStream.getValueOr(DefaultDbiStream);
auto &DbiBuilder = Builder.getDbiBuilder();
DbiBuilder.setAge(Dbi.Age);
DbiBuilder.setBuildNumber(Dbi.BuildNumber);
DbiBuilder.setFlags(Dbi.Flags);
DbiBuilder.setMachineType(Dbi.MachineType);
DbiBuilder.setPdbDllRbld(Dbi.PdbDllRbld);
DbiBuilder.setPdbDllVersion(Dbi.PdbDllVersion);
DbiBuilder.setVersionHeader(Dbi.VerHeader);
for (const auto &MI : Dbi.ModInfos) {
auto &ModiBuilder = ExitOnErr(DbiBuilder.addModuleInfo(MI.Obj));
for (auto S : MI.SourceFiles)
ExitOnErr(DbiBuilder.addModuleSourceFile(MI.Mod, S));
if (MI.Modi.hasValue()) {
const auto &ModiStream = *MI.Modi;
ModiBuilder.setObjFileName(MI.Obj);
for (auto Symbol : ModiStream.Symbols)
ModiBuilder.addSymbol(Symbol.Record);
}
}
if (YamlObj.TpiStream.hasValue()) {
auto &TpiBuilder = Builder.getTpiBuilder();
TpiBuilder.setVersionHeader(YamlObj.TpiStream->Version);
for (const auto &R : YamlObj.TpiStream->Records)
TpiBuilder.addTypeRecord(R.Record);
}
auto &TpiBuilder = Builder.getTpiBuilder();
const auto &Tpi = YamlObj.TpiStream.getValueOr(DefaultTpiStream);
TpiBuilder.setVersionHeader(Tpi.Version);
for (const auto &R : Tpi.Records)
TpiBuilder.addTypeRecord(R.Record);
if (YamlObj.IpiStream.hasValue()) {
auto &IpiBuilder = Builder.getIpiBuilder();
IpiBuilder.setVersionHeader(YamlObj.IpiStream->Version);
for (const auto &R : YamlObj.IpiStream->Records)
IpiBuilder.addTypeRecord(R.Record);
}
const auto &Ipi = YamlObj.IpiStream.getValueOr(DefaultTpiStream);
auto &IpiBuilder = Builder.getIpiBuilder();
IpiBuilder.setVersionHeader(Ipi.Version);
for (const auto &R : Ipi.Records)
IpiBuilder.addTypeRecord(R.Record);
ExitOnErr(Builder.commit(opts::yaml2pdb::YamlPdbOutputFile));
}

View File

@ -73,6 +73,7 @@ extern llvm::cl::opt<bool> Pedantic;
namespace pdb2yaml {
extern llvm::cl::opt<bool> NoFileHeaders;
extern llvm::cl::opt<bool> Minimal;
extern llvm::cl::opt<bool> StreamMetadata;
extern llvm::cl::opt<bool> StreamDirectory;
extern llvm::cl::opt<bool> StringTable;