summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/COFF/PDB.cpp2
-rw-r--r--llvm/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h17
-rw-r--r--llvm/include/llvm/DebugInfo/PDB/Native/ModInfoBuilder.h74
-rw-r--r--llvm/include/llvm/DebugInfo/PDB/Native/RawError.h1
-rw-r--r--llvm/include/llvm/Support/BinaryStreamWriter.h1
-rw-r--r--llvm/lib/DebugInfo/PDB/CMakeLists.txt1
-rw-r--r--llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp111
-rw-r--r--llvm/lib/DebugInfo/PDB/Native/ModInfoBuilder.cpp136
-rw-r--r--llvm/lib/DebugInfo/PDB/Native/RawError.cpp2
-rw-r--r--llvm/lib/Support/BinaryStreamWriter.cpp9
-rw-r--r--llvm/test/DebugInfo/PDB/Inputs/one-symbol.yaml11
-rw-r--r--llvm/test/DebugInfo/PDB/pdb-minimal-construct.test11
-rw-r--r--llvm/test/DebugInfo/PDB/pdbdump-yaml-types.test4
-rw-r--r--llvm/tools/llvm-pdbdump/PdbYaml.cpp51
-rw-r--r--llvm/tools/llvm-pdbdump/PdbYaml.h28
-rw-r--r--llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp4
-rw-r--r--llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp88
-rw-r--r--llvm/tools/llvm-pdbdump/llvm-pdbdump.h1
18 files changed, 392 insertions, 160 deletions
diff --git a/lld/COFF/PDB.cpp b/lld/COFF/PDB.cpp
index f749c37e2a7..5af93e86364 100644
--- a/lld/COFF/PDB.cpp
+++ b/lld/COFF/PDB.cpp
@@ -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(
diff --git a/llvm/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h b/llvm/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h
index 23c74ae8de1..16426bd9384 100644
--- a/llvm/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h
+++ b/llvm/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h
@@ -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;
diff --git a/llvm/include/llvm/DebugInfo/PDB/Native/ModInfoBuilder.h b/llvm/include/llvm/DebugInfo/PDB/Native/ModInfoBuilder.h
new file mode 100644
index 00000000000..605fd2483c3
--- /dev/null
+++ b/llvm/include/llvm/DebugInfo/PDB/Native/ModInfoBuilder.h
@@ -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
diff --git a/llvm/include/llvm/DebugInfo/PDB/Native/RawError.h b/llvm/include/llvm/DebugInfo/PDB/Native/RawError.h
index f96b8066bbe..3624a7682e3 100644
--- a/llvm/include/llvm/DebugInfo/PDB/Native/RawError.h
+++ b/llvm/include/llvm/DebugInfo/PDB/Native/RawError.h
@@ -28,6 +28,7 @@ enum class raw_error_code {
duplicate_entry,
no_entry,
not_writable,
+ stream_too_long,
invalid_tpi_hash,
};
diff --git a/llvm/include/llvm/Support/BinaryStreamWriter.h b/llvm/include/llvm/Support/BinaryStreamWriter.h
index acc979c66d5..64f26b24543 100644
--- a/llvm/include/llvm/Support/BinaryStreamWriter.h
+++ b/llvm/include/llvm/Support/BinaryStreamWriter.h
@@ -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;
diff --git a/llvm/lib/DebugInfo/PDB/CMakeLists.txt b/llvm/lib/DebugInfo/PDB/CMakeLists.txt
index 1b9dd2b651d..448b6a369b0 100644
--- a/llvm/lib/DebugInfo/PDB/CMakeLists.txt
+++ b/llvm/lib/DebugInfo/PDB/CMakeLists.txt
@@ -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
diff --git a/llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp
index efd7f127a19..a203aea60fe 100644
--- a/llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp
@@ -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;
diff --git a/llvm/lib/DebugInfo/PDB/Native/ModInfoBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/ModInfoBuilder.cpp
new file mode 100644
index 00000000000..73c45a95352
--- /dev/null
+++ b/llvm/lib/DebugInfo/PDB/Native/ModInfoBuilder.cpp
@@ -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();
+}
diff --git a/llvm/lib/DebugInfo/PDB/Native/RawError.cpp b/llvm/lib/DebugInfo/PDB/Native/RawError.cpp
index aa126bb8f1a..548289fff3d 100644
--- a/llvm/lib/DebugInfo/PDB/Native/RawError.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/RawError.cpp
@@ -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.";
}
diff --git a/llvm/lib/Support/BinaryStreamWriter.cpp b/llvm/lib/Support/BinaryStreamWriter.cpp
index 487bcdc5a4d..d60b75642d0 100644
--- a/llvm/lib/Support/BinaryStreamWriter.cpp
+++ b/llvm/lib/Support/BinaryStreamWriter.cpp
@@ -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();
+}
diff --git a/llvm/test/DebugInfo/PDB/Inputs/one-symbol.yaml b/llvm/test/DebugInfo/PDB/Inputs/one-symbol.yaml
new file mode 100644
index 00000000000..5728f05d490
--- /dev/null
+++ b/llvm/test/DebugInfo/PDB/Inputs/one-symbol.yaml
@@ -0,0 +1,11 @@
+---
+DbiStream:
+ Modules:
+ - Module: one-symbol.yaml
+ Modi:
+ Records:
+ - Kind: S_OBJNAME
+ ObjNameSym:
+ Signature: 0
+ ObjectName: 'c:\foo\one-symbol.yaml'
+...
diff --git a/llvm/test/DebugInfo/PDB/pdb-minimal-construct.test b/llvm/test/DebugInfo/PDB/pdb-minimal-construct.test
new file mode 100644
index 00000000000..d75c51056c9
--- /dev/null
+++ b/llvm/test/DebugInfo/PDB/pdb-minimal-construct.test
@@ -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
diff --git a/llvm/test/DebugInfo/PDB/pdbdump-yaml-types.test b/llvm/test/DebugInfo/PDB/pdbdump-yaml-types.test
index 25895f3de2f..7e6fcc1ca42 100644
--- a/llvm/test/DebugInfo/PDB/pdbdump-yaml-types.test
+++ b/llvm/test/DebugInfo/PDB/pdbdump-yaml-types.test
@@ -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:
diff --git a/llvm/tools/llvm-pdbdump/PdbYaml.cpp b/llvm/tools/llvm-pdbdump/PdbYaml.cpp
index 9877af0a07c..21f5a775c55 100644
--- a/llvm/tools/llvm-pdbdump/PdbYaml.cpp
+++ b/llvm/tools/llvm-pdbdump/PdbYaml.cpp
@@ -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);
}
diff --git a/llvm/tools/llvm-pdbdump/PdbYaml.h b/llvm/tools/llvm-pdbdump/PdbYaml.h
index 3b9b8e5c813..7632d7e0b60 100644
--- a/llvm/tools/llvm-pdbdump/PdbYaml.h
+++ b/llvm/tools/llvm-pdbdump/PdbYaml.h
@@ -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;
};
diff --git a/llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp b/llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp
index 065a60d32a8..fab3760fabb 100644
--- a/llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp
+++ b/llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp
@@ -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)
diff --git a/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp b/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp
index c4bdab26067..7dd4eec1fe5 100644
--- a/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp
+++ b/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp
@@ -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);
- }
-
- 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));
+ pdb::yaml::PdbInfoStream DefaultInfoStream;
+ pdb::yaml::PdbDbiStream DefaultDbiStream;
+ pdb::yaml::PdbTpiStream DefaultTpiStream;
+
+ 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);
- }
-
- if (YamlObj.IpiStream.hasValue()) {
- auto &IpiBuilder = Builder.getIpiBuilder();
- IpiBuilder.setVersionHeader(YamlObj.IpiStream->Version);
- for (const auto &R : YamlObj.IpiStream->Records)
- IpiBuilder.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);
+
+ 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));
}
diff --git a/llvm/tools/llvm-pdbdump/llvm-pdbdump.h b/llvm/tools/llvm-pdbdump/llvm-pdbdump.h
index cdebc20fb5f..0cf31c8163b 100644
--- a/llvm/tools/llvm-pdbdump/llvm-pdbdump.h
+++ b/llvm/tools/llvm-pdbdump/llvm-pdbdump.h
@@ -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;
OpenPOWER on IntegriCloud