uint32_t getAge() const;
PDB_UniqueId getGuid() const;
+ const NamedStreamMap &getNamedStreams() const;
+
uint32_t getNamedStreamIndex(llvm::StringRef Name) const;
iterator_range<StringMapConstIterator<uint32_t>> named_streams() const;
}
namespace pdb {
class PDBFile;
+class NamedStreamMap;
class InfoStreamBuilder {
public:
- InfoStreamBuilder(msf::MSFBuilder &Msf);
+ InfoStreamBuilder(msf::MSFBuilder &Msf, NamedStreamMap &NamedStreams);
InfoStreamBuilder(const InfoStreamBuilder &) = delete;
InfoStreamBuilder &operator=(const InfoStreamBuilder &) = delete;
void setAge(uint32_t A);
void setGuid(PDB_UniqueId G);
- NamedStreamMap &getNamedStreamsBuilder();
-
uint32_t finalize();
Error finalizeMsfLayout();
uint32_t Age;
PDB_UniqueId Guid;
- NamedStreamMap NamedStreams;
+ NamedStreamMap &NamedStreams;
};
}
}
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/Optional.h"
+#include "llvm/DebugInfo/PDB/Raw/NamedStreamMap.h"
#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
#include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
+#include "llvm/DebugInfo/PDB/Raw/StringTableBuilder.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"
DbiStreamBuilder &getDbiBuilder();
TpiStreamBuilder &getTpiBuilder();
TpiStreamBuilder &getIpiBuilder();
+ StringTableBuilder &getStringTableBuilder();
Error commit(StringRef Filename);
private:
- Expected<msf::MSFLayout> finalizeMsfLayout() const;
+ Error addNamedStream(StringRef Name, uint32_t Size);
+ Expected<msf::MSFLayout> finalizeMsfLayout();
BumpPtrAllocator &Allocator;
std::unique_ptr<DbiStreamBuilder> Dbi;
std::unique_ptr<TpiStreamBuilder> Tpi;
std::unique_ptr<TpiStreamBuilder> Ipi;
+
+ StringTableBuilder Strings;
+ NamedStreamMap NamedStreams;
};
}
}
// Returns the ID for S.
uint32_t insert(StringRef S);
- uint32_t calculateSerializedLength() const;
+ uint32_t finalize();
Error commit(msf::StreamWriter &Writer) const;
private:
uint32_t InfoStream::getAge() const { return Age; }
PDB_UniqueId InfoStream::getGuid() const { return Guid; }
+
+const NamedStreamMap &InfoStream::getNamedStreams() const {
+ return NamedStreams;
+}
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
#include "llvm/DebugInfo/MSF/StreamWriter.h"
#include "llvm/DebugInfo/PDB/Raw/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Raw/NamedStreamMap.h"
+#include "llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h"
#include "llvm/DebugInfo/PDB/Raw/RawError.h"
#include "llvm/DebugInfo/PDB/Raw/RawTypes.h"
using namespace llvm::msf;
using namespace llvm::pdb;
-InfoStreamBuilder::InfoStreamBuilder(msf::MSFBuilder &Msf)
- : Msf(Msf), Ver(PdbRaw_ImplVer::PdbImplVC70), Sig(-1), Age(0) {}
+InfoStreamBuilder::InfoStreamBuilder(msf::MSFBuilder &Msf,
+ NamedStreamMap &NamedStreams)
+ : Msf(Msf), Ver(PdbRaw_ImplVer::PdbImplVC70), Sig(-1), Age(0),
+ NamedStreams(NamedStreams) {}
void InfoStreamBuilder::setVersion(PdbRaw_ImplVer V) { Ver = V; }
void InfoStreamBuilder::setGuid(PDB_UniqueId G) { Guid = G; }
-NamedStreamMap &InfoStreamBuilder::getNamedStreamsBuilder() {
- return NamedStreams;
-}
-
Error InfoStreamBuilder::finalizeMsfLayout() {
uint32_t Length = sizeof(InfoStreamHeader) + NamedStreams.finalize();
if (auto EC = Msf.setStreamSize(StreamPDB, Length))
#include "llvm/DebugInfo/PDB/Raw/InfoStream.h"
#include "llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h"
#include "llvm/DebugInfo/PDB/Raw/RawError.h"
+#include "llvm/DebugInfo/PDB/Raw/StringTableBuilder.h"
#include "llvm/DebugInfo/PDB/Raw/TpiStream.h"
#include "llvm/DebugInfo/PDB/Raw/TpiStreamBuilder.h"
InfoStreamBuilder &PDBFileBuilder::getInfoBuilder() {
if (!Info)
- Info = llvm::make_unique<InfoStreamBuilder>(*Msf);
+ Info = llvm::make_unique<InfoStreamBuilder>(*Msf, NamedStreams);
return *Info;
}
return *Ipi;
}
-Expected<msf::MSFLayout> PDBFileBuilder::finalizeMsfLayout() const {
+StringTableBuilder &PDBFileBuilder::getStringTableBuilder() { return Strings; }
+
+Error PDBFileBuilder::addNamedStream(StringRef Name, uint32_t Size) {
+ auto ExpectedStream = Msf->addStream(Size);
+ if (!ExpectedStream)
+ return ExpectedStream.takeError();
+ NamedStreams.set(Name, *ExpectedStream);
+ return Error::success();
+}
+
+Expected<msf::MSFLayout> PDBFileBuilder::finalizeMsfLayout() {
+ uint32_t StringTableSize = Strings.finalize();
+
+ if (auto EC = addNamedStream("/names", StringTableSize))
+ return std::move(EC);
+ if (auto EC = addNamedStream("/LinkInfo", 0))
+ return std::move(EC);
+ if (auto EC = addNamedStream("/src/headerblock", 0))
+ return std::move(EC);
+
if (Info) {
if (auto EC = Info->finalizeMsfLayout())
return std::move(EC);
return EC;
}
+ uint32_t StringTableStreamNo = 0;
+ if (!NamedStreams.get("/names", StringTableStreamNo))
+ return llvm::make_error<pdb::RawError>(raw_error_code::no_stream);
+
+ auto NS = WritableMappedBlockStream::createIndexedStream(Layout, Buffer,
+ StringTableStreamNo);
+ StreamWriter NSWriter(*NS);
+ if (auto EC = Strings.commit(NSWriter))
+ return EC;
+
if (Info) {
if (auto EC = Info->commit(Layout, Buffer))
return EC;
return (NumStrings + 1) * 1.25;
}
-uint32_t StringTableBuilder::calculateSerializedLength() const {
+uint32_t StringTableBuilder::finalize() {
uint32_t Size = 0;
Size += sizeof(StringTableHeader);
Size += StringSize;
- Size += 4; // Hash table begins with 4-byte size field.
+ Size += sizeof(uint32_t); // Hash table begins with 4-byte size field.
uint32_t BucketCount = computeBucketCount(Strings.size());
- Size += BucketCount * 4;
+ Size += BucketCount * sizeof(uint32_t);
- Size += 4; // The /names stream ends with the number of strings.
+ Size +=
+ sizeof(uint32_t); // The /names stream ends with the number of strings.
return Size;
}
-; RUN: llvm-pdbdump raw -headers -tpi-records -tpi-record-bytes -module-syms \
+; RUN: llvm-pdbdump raw -headers -string-table -tpi-records -tpi-record-bytes -module-syms \
; RUN: -sym-record-bytes -globals -publics -module-files \
; RUN: -stream-summary -stream-blocks -ipi-records -ipi-record-bytes \
; RUN: -section-contribs -section-map -section-headers -line-info \
; EMPTY-NEXT: Stream 15: [21]
; EMPTY-NEXT: Stream 16: [22]
; EMPTY-NEXT: ]
+; EMPTY-NEXT: String Table {
+; EMPTY-NEXT: 'd:\src\llvm\test\debuginfo\pdb\inputs\predefined c++ attributes (compiler internal)'
+; EMPTY-NEXT: 'd:\src\llvm\test\debuginfo\pdb\inputs\empty.cpp'
+; EMPTY-NEXT: '$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = '
+; EMPTY-NEXT: }
; EMPTY-NEXT: PDB Stream {
; EMPTY-NEXT: Version: 20000404
; EMPTY-NEXT: Signature: 0x54E507E2
; EMPTY-NEXT: Age: 1
; EMPTY-NEXT: Guid: {0B355641-86A0-A249-896F-9988FAE52FF0}
+; EMPTY-NEXT: Named Streams {
+; EMPTY-NEXT: /names: 13
+; EMPTY-NEXT: /LinkInfo: 5
+; EMPTY-NEXT: /src/headerblock: 9
+; EMPTY-NEXT: }
; EMPTY-NEXT: }
; EMPTY-NEXT: Type Info Stream (TPI) {
; EMPTY-NEXT: TPI Version: 20040203
; BIG-NEXT: Signature: 0x571FFE67
; BIG-NEXT: Age: 1
; BIG-NEXT: Guid: {880ECC89-DF81-0B4F-839C-58CBD052E937}
+; BIG-NEXT: Named Streams {
+; BIG-NEXT: /names: 13
+; BIG-NEXT: /LinkInfo: 5
+; BIG-NEXT: /src/headerblock: 61
+; BIG-NEXT: }
; BIG-NEXT: }
; BIG-NEXT: DBI Stream {
; BIG-NEXT: Dbi Version: 19990903
RUN: llvm-pdbdump pdb2yaml -dbi-module-info -dbi-module-source-info \
-RUN: -dbi-stream -pdb-stream -tpi-stream -stream-directory \
+RUN: -dbi-stream -pdb-stream -string-table -tpi-stream -stream-directory \
RUN: -stream-metadata %p/Inputs/empty.pdb > %t.1
RUN: llvm-pdbdump yaml2pdb -pdb=%t.2 %t.1
-RUN: llvm-pdbdump raw -headers -tpi-records %p/Inputs/empty.pdb | FileCheck %s
-RUN: llvm-pdbdump raw -headers -tpi-records %t.2 | FileCheck %s
+RUN: llvm-pdbdump raw -headers -string-table -tpi-records %p/Inputs/empty.pdb | FileCheck %s
+RUN: llvm-pdbdump raw -headers -string-table -tpi-records %t.2 | FileCheck %s
CHECK: FileHeaders {
CHECK-NEXT: BlockSize: 4096
CHECK-NEXT: DirectoryBlocks:
CHECK-NEXT: NumStreams:
CHECK-NEXT: }
+CHECK: String Table {
+CHECK-DAG: 'd:\src\llvm\test\debuginfo\pdb\inputs\predefined c++ attributes (compiler internal)'
+CHECK-DAG: 'd:\src\llvm\test\debuginfo\pdb\inputs\empty.cpp'
+CHECK-DAG: '$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = '
+CHECK-NEXT: }
CHECK: PDB Stream {
CHECK-NEXT: Version: 20000404
CHECK-NEXT: Signature: 0x54E507E2
CHECK-NEXT: Age: 1
CHECK-NEXT: Guid: {0B355641-86A0-A249-896F-9988FAE52FF0}
+CHECK-NEXT: Named Streams {
+CHECK: /names:
+CHECK: }
CHECK-NEXT: }
CHECK: Type Info Stream (TPI) {
CHECK-NEXT: TPI Version: 20040203
; stream metadata, since the layout of the MSF file might be different
; (for example if we don't write the entire stream)
;
-; RUN: llvm-pdbdump pdb2yaml -stream-metadata -stream-directory -pdb-stream -tpi-stream %p/Inputs/empty.pdb > %t.1
+; RUN: llvm-pdbdump pdb2yaml -stream-metadata -stream-directory \
+; RUN: -pdb-stream -tpi-stream %p/Inputs/empty.pdb > %t.1
; RUN: llvm-pdbdump yaml2pdb -pdb=%t.2 %t.1
-; RUN: llvm-pdbdump pdb2yaml -pdb-stream -tpi-stream -no-file-headers %p/Inputs/empty.pdb > %t.3
-; RUN: llvm-pdbdump pdb2yaml -pdb-stream -tpi-stream -no-file-headers %t.2 > %t.4
+; RUN: llvm-pdbdump pdb2yaml -pdb-stream -tpi-stream \
+; RUN: -no-file-headers %p/Inputs/empty.pdb > %t.3
+; RUN: llvm-pdbdump pdb2yaml -pdb-stream -tpi-stream \
+; RUN: -no-file-headers %t.2 > %t.4
; RUN: diff %t.3 %t.4
-; RUN: llvm-pdbdump pdb2yaml -stream-metadata -stream-directory -pdb-stream %p/Inputs/empty.pdb \
-; RUN: | FileCheck -check-prefix=YAML %s
+; RUN: llvm-pdbdump pdb2yaml -stream-metadata -stream-directory -string-table -pdb-stream \
+; RUN: %p/Inputs/empty.pdb | FileCheck -check-prefix=YAML %s
; RUN: llvm-pdbdump pdb2yaml -no-file-headers -stream-metadata -stream-directory -pdb-stream \
; RUN: %p/Inputs/empty.pdb | FileCheck -check-prefix=NO-HEADERS %s
; YAML-NEXT: - Stream: [ 7 ]
; YAML-NEXT: - Stream: [ 21 ]
; YAML-NEXT: - Stream: [ 22 ]
+; YAML-NEXT: StringTable:
+; YAML-NEXT: - 'd:\src\llvm\test\debuginfo\pdb\inputs\predefined c++ attributes (compiler internal)'
+; YAML-NEXT: - 'd:\src\llvm\test\debuginfo\pdb\inputs\empty.cpp'
+; YAML-NEXT: - '$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = '
; YAML-NEXT: PdbStream:
; YAML-NEXT: Age: 1
; YAML-NEXT: Guid: '{0B355641-86A0-A249-896F-9988FAE52FF0}'
; YAML-NEXT: Signature: 1424295906
; YAML-NEXT: Version: VC70
-; YAML-NEXT: NamedStreams:
-; YAML-NEXT: - Name: /names
-; YAML-NEXT: StreamNum: 13
-; YAML-NEXT: - Name: /LinkInfo
-; YAML-NEXT: StreamNum: 5
-; YAML-NEXT: - Name: /src/headerblock
-; YAML-NEXT: StreamNum: 9
; YAML-NEXT: ...
; NO-HEADERS: ---
if (auto EC = dumpStreamBytes())
return EC;
+ if (auto EC = dumpStringTable())
+ return EC;
+
if (auto EC = dumpInfoStream())
return EC;
return Error::success();
}
+Error LLVMOutputStyle::dumpStringTable() {
+ if (!opts::raw::DumpStringTable)
+ return Error::success();
+
+ auto IS = File.getStringTable();
+ if (!IS)
+ return IS.takeError();
+
+ DictScope D(P, "String Table");
+ for (uint32_t I : IS->name_ids()) {
+ StringRef S = IS->getStringForID(I);
+ if (!S.empty()) {
+ llvm::SmallString<32> Str;
+ Str.append("'");
+ Str.append(S);
+ Str.append("'");
+ P.printString(Str);
+ }
+ }
+ return Error::success();
+}
+
Error LLVMOutputStyle::dumpInfoStream() {
if (!opts::raw::DumpHeaders)
return Error::success();
P.printHex("Signature", IS->getSignature());
P.printNumber("Age", IS->getAge());
P.printObject("Guid", IS->getGuid());
+ {
+ DictScope DD(P, "Named Streams");
+ for (const auto &S : IS->getNamedStreams().entries())
+ P.printObject(S.getKey(), S.getValue());
+ }
return Error::success();
}
Error dumpGlobalsStream();
Error dumpStreamBytes();
Error dumpStreamBlocks();
+ Error dumpStringTable();
Error dumpInfoStream();
Error dumpTpiStream(uint32_t StreamIdx);
Error dumpDbiStream();
IO.mapOptional("MSF", Obj.Headers);
IO.mapOptional("StreamSizes", Obj.StreamSizes);
IO.mapOptional("StreamMap", Obj.StreamMap);
+ IO.mapOptional("StringTable", Obj.StringTable);
IO.mapOptional("PdbStream", Obj.PdbStream);
IO.mapOptional("DbiStream", Obj.DbiStream);
IO.mapOptionalWithContext("TpiStream", Obj.TpiStream, Obj.Allocator);
IO.mapRequired("Guid", Obj.Guid);
IO.mapRequired("Signature", Obj.Signature);
IO.mapRequired("Version", Obj.Version);
- IO.mapRequired("NamedStreams", Obj.NamedStreams);
}
void MappingTraits<PdbDbiStream>::mapping(IO &IO, PdbDbiStream &Obj) {
Optional<PdbTpiStream> TpiStream;
Optional<PdbTpiStream> IpiStream;
+ Optional<std::vector<StringRef>> StringTable;
+
BumpPtrAllocator &Allocator;
};
}
if (auto EC = dumpStreamDirectory())
return EC;
+ if (auto EC = dumpStringTable())
+ return EC;
+
if (auto EC = dumpPDBStream())
return EC;
return Error::success();
}
+Error YAMLOutputStyle::dumpStringTable() {
+ if (!opts::pdb2yaml::StringTable)
+ return Error::success();
+
+ Obj.StringTable.emplace();
+ auto ExpectedST = File.getStringTable();
+ if (!ExpectedST)
+ return ExpectedST.takeError();
+
+ const auto &ST = ExpectedST.get();
+ for (auto ID : ST.name_ids()) {
+ StringRef S = ST.getStringForID(ID);
+ if (!S.empty())
+ Obj.StringTable->push_back(S);
+ }
+ return Error::success();
+}
+
Error YAMLOutputStyle::dumpStreamMetadata() {
if (!opts::pdb2yaml::StreamMetadata)
return Error::success();
Obj.PdbStream->Guid = InfoS.getGuid();
Obj.PdbStream->Signature = InfoS.getSignature();
Obj.PdbStream->Version = InfoS.getVersion();
- for (auto &NS : InfoS.named_streams()) {
- yaml::NamedStreamMapping Mapping;
- Mapping.StreamName = NS.getKey();
- Mapping.StreamNumber = NS.getValue();
- Obj.PdbStream->NamedStreams.push_back(Mapping);
- }
return Error::success();
}
Error dump() override;
private:
+ Error dumpStringTable();
Error dumpFileHeaders();
Error dumpStreamMetadata();
Error dumpStreamDirectory();
#include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
#include "llvm/DebugInfo/PDB/Raw/RawError.h"
#include "llvm/DebugInfo/PDB/Raw/RawSession.h"
+#include "llvm/DebugInfo/PDB/Raw/StringTableBuilder.h"
#include "llvm/DebugInfo/PDB/Raw/TpiStream.h"
#include "llvm/DebugInfo/PDB/Raw/TpiStreamBuilder.h"
#include "llvm/Support/COM.h"
cl::cat(SymbolOptions), cl::sub(RawSubcommand));
// MISCELLANEOUS OPTIONS
+cl::opt<bool> DumpStringTable("string-table", cl::desc("dump PDB String Table"),
+ cl::cat(MiscOptions), cl::sub(RawSubcommand));
+
cl::opt<bool> DumpSectionContribs("section-contribs",
cl::desc("dump section contributions"),
cl::cat(MiscOptions), cl::sub(RawSubcommand));
cl::opt<bool> PdbStream("pdb-stream",
cl::desc("Dump the PDB Stream (Stream 1)"),
cl::sub(PdbToYamlSubcommand), cl::init(false));
+
+cl::opt<bool> StringTable("string-table", cl::desc("Dump the PDB String Table"),
+ cl::sub(PdbToYamlSubcommand), cl::init(false));
+
cl::opt<bool> DbiStream("dbi-stream",
cl::desc("Dump the DBI Stream (Stream 2)"),
cl::sub(PdbToYamlSubcommand), cl::init(false));
for (uint32_t I = 0; I < kSpecialStreamCount; ++I)
ExitOnErr(Builder.getMsfBuilder().addStream(0));
+ if (YamlObj.StringTable.hasValue()) {
+ auto &Strings = Builder.getStringTableBuilder();
+ for (auto S : *YamlObj.StringTable)
+ 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);
- for (auto &NM : YamlObj.PdbStream->NamedStreams)
- InfoBuilder.getNamedStreamsBuilder().set(NM.StreamName, NM.StreamNumber);
}
if (YamlObj.DbiStream.hasValue()) {
opts::raw::DumpSectionContribs = true;
opts::raw::DumpLineInfo = true;
opts::raw::DumpFpo = true;
+ opts::raw::DumpStringTable = true;
}
if (opts::raw::CompactRecords &&
extern llvm::cl::opt<bool> DumpSymRecordBytes;
extern llvm::cl::opt<bool> DumpSectionHeaders;
extern llvm::cl::opt<bool> DumpFpo;
+extern llvm::cl::opt<bool> DumpStringTable;
}
namespace pdb2yaml {
extern llvm::cl::opt<bool> NoFileHeaders;
extern llvm::cl::opt<bool> StreamMetadata;
extern llvm::cl::opt<bool> StreamDirectory;
+extern llvm::cl::opt<bool> StringTable;
extern llvm::cl::opt<bool> PdbStream;
extern llvm::cl::opt<bool> DbiStream;
extern llvm::cl::opt<bool> DbiModuleInfo;
EXPECT_EQ(1U, Builder.insert("foo"));
EXPECT_EQ(9U, Builder.insert("baz"));
- std::vector<uint8_t> Buffer(Builder.calculateSerializedLength());
+ std::vector<uint8_t> Buffer(Builder.finalize());
msf::MutableByteStream OutStream(Buffer);
msf::StreamWriter Writer(OutStream);
EXPECT_NO_ERROR(Builder.commit(Writer));