[PDB] Add support for parsing Flags from PDB Stream.

This was discovered when running `llvm-pdbdump diff` against
two files, the second of which was generated by running the
first one through pdb2yaml and then yaml2pdb.

The second one was missing some bytes from the PDB Stream, and
tracking this down showed that at the end of the PDB Stream were
some additional bytes that we were ignoring.  Looking back
to the reference code, these seem to specify some additional
flags that indicate whether the PDB supports various optional
features.

This patch adds support for reading, writing, and round-tripping
these flags through YAML and the raw dumper, and updates the
tests accordingly.

llvm-svn: 297984
This commit is contained in:
Zachary Turner 2017-03-16 20:19:11 +00:00
parent 02278ce09f
commit 05d5e6136f
14 changed files with 134 additions and 3 deletions

View File

@ -10,6 +10,7 @@
#ifndef LLVM_DEBUGINFO_PDB_RAW_PDBINFOSTREAM_H #ifndef LLVM_DEBUGINFO_PDB_RAW_PDBINFOSTREAM_H
#define LLVM_DEBUGINFO_PDB_RAW_PDBINFOSTREAM_H #define LLVM_DEBUGINFO_PDB_RAW_PDBINFOSTREAM_H
#include "llvm/ADT/BitmaskEnum.h"
#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringMap.h"
#include "llvm/DebugInfo/MSF/MappedBlockStream.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
#include "llvm/DebugInfo/PDB/Native/NamedStreamMap.h" #include "llvm/DebugInfo/PDB/Native/NamedStreamMap.h"
@ -40,6 +41,9 @@ public:
PDB_UniqueId getGuid() const; PDB_UniqueId getGuid() const;
uint32_t getNamedStreamMapByteSize() const; uint32_t getNamedStreamMapByteSize() const;
PdbRaw_Features getFeatures() const;
ArrayRef<PdbRaw_FeatureSig> getFeatureSignatures() const;
const NamedStreamMap &getNamedStreams() const; const NamedStreamMap &getNamedStreams() const;
uint32_t getNamedStreamIndex(llvm::StringRef Name) const; uint32_t getNamedStreamIndex(llvm::StringRef Name) const;
@ -66,6 +70,9 @@ private:
// universally unique. // universally unique.
PDB_UniqueId Guid; PDB_UniqueId Guid;
std::vector<PdbRaw_FeatureSig> FeatureSignatures;
PdbRaw_Features Features = PdbFeatureNone;
uint32_t NamedStreamMapByteSize = 0; uint32_t NamedStreamMapByteSize = 0;
NamedStreamMap NamedStreams; NamedStreamMap NamedStreams;

View File

@ -38,6 +38,7 @@ public:
void setSignature(uint32_t S); void setSignature(uint32_t S);
void setAge(uint32_t A); void setAge(uint32_t A);
void setGuid(PDB_UniqueId G); void setGuid(PDB_UniqueId G);
void addFeature(PdbRaw_FeatureSig Sig);
uint32_t finalize(); uint32_t finalize();
@ -49,6 +50,7 @@ public:
private: private:
msf::MSFBuilder &Msf; msf::MSFBuilder &Msf;
std::vector<PdbRaw_FeatureSig> Features;
PdbRaw_ImplVer Ver; PdbRaw_ImplVer Ver;
uint32_t Sig; uint32_t Sig;
uint32_t Age; uint32_t Age;

View File

@ -10,6 +10,7 @@
#ifndef LLVM_DEBUGINFO_PDB_RAW_PDBRAWCONSTANTS_H #ifndef LLVM_DEBUGINFO_PDB_RAW_PDBRAWCONSTANTS_H
#define LLVM_DEBUGINFO_PDB_RAW_PDBRAWCONSTANTS_H #define LLVM_DEBUGINFO_PDB_RAW_PDBRAWCONSTANTS_H
#include "llvm/ADT/BitmaskEnum.h"
#include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/CodeView.h"
#include <cstdint> #include <cstdint>
@ -32,6 +33,21 @@ enum PdbRaw_ImplVer : uint32_t {
PdbImplVC140 = 20140508, PdbImplVC140 = 20140508,
}; };
enum class PdbRaw_FeatureSig : uint32_t {
VC110 = PdbImplVC110,
VC140 = PdbImplVC140,
NoTypeMerge = 0x4D544F4E,
MinimalDebugInfo = 0x494E494D,
};
enum PdbRaw_Features : uint32_t {
PdbFeatureNone = 0x0,
PdbFeatureContainsIdStream = 0x1,
PdbFeatureMinimalDebugInfo = 0x2,
PdbFeatureNoTypeMerging = 0x4,
LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ PdbFeatureNoTypeMerging)
};
enum PdbRaw_DbiVer : uint32_t { enum PdbRaw_DbiVer : uint32_t {
PdbDbiVC41 = 930803, PdbDbiVC41 = 930803,
PdbDbiV50 = 19960307, PdbDbiV50 = 19960307,

View File

@ -56,6 +56,30 @@ Error InfoStream::reload() {
return EC; return EC;
uint32_t NewOffset = Reader.getOffset(); uint32_t NewOffset = Reader.getOffset();
NamedStreamMapByteSize = NewOffset - Offset; NamedStreamMapByteSize = NewOffset - Offset;
bool Stop = false;
while (!Stop && !Reader.empty()) {
PdbRaw_FeatureSig Sig;
if (auto EC = Reader.readEnum(Sig))
return EC;
switch (Sig) {
case PdbRaw_FeatureSig::VC110:
// No other flags for VC110 PDB.
Stop = true;
LLVM_FALLTHROUGH;
case PdbRaw_FeatureSig::VC140:
Features |= PdbFeatureContainsIdStream;
break;
case PdbRaw_FeatureSig::NoTypeMerge:
Features |= PdbFeatureNoTypeMerging;
break;
case PdbRaw_FeatureSig::MinimalDebugInfo:
Features |= PdbFeatureMinimalDebugInfo;
default:
continue;
}
FeatureSignatures.push_back(Sig);
}
return Error::success(); return Error::success();
} }
@ -87,6 +111,12 @@ uint32_t InfoStream::getNamedStreamMapByteSize() const {
return NamedStreamMapByteSize; return NamedStreamMapByteSize;
} }
PdbRaw_Features InfoStream::getFeatures() const { return Features; }
ArrayRef<PdbRaw_FeatureSig> InfoStream::getFeatureSignatures() const {
return FeatureSignatures;
}
const NamedStreamMap &InfoStream::getNamedStreams() const { const NamedStreamMap &InfoStream::getNamedStreams() const {
return NamedStreams; return NamedStreams;
} }

View File

@ -36,8 +36,13 @@ void InfoStreamBuilder::setAge(uint32_t A) { Age = A; }
void InfoStreamBuilder::setGuid(PDB_UniqueId G) { Guid = G; } void InfoStreamBuilder::setGuid(PDB_UniqueId G) { Guid = G; }
void InfoStreamBuilder::addFeature(PdbRaw_FeatureSig Sig) {
Features.push_back(Sig);
}
Error InfoStreamBuilder::finalizeMsfLayout() { Error InfoStreamBuilder::finalizeMsfLayout() {
uint32_t Length = sizeof(InfoStreamHeader) + NamedStreams.finalize(); uint32_t Length = sizeof(InfoStreamHeader) + NamedStreams.finalize() +
(Features.size() + 1) * sizeof(uint32_t);
if (auto EC = Msf.setStreamSize(StreamPDB, Length)) if (auto EC = Msf.setStreamSize(StreamPDB, Length))
return EC; return EC;
return Error::success(); return Error::success();
@ -57,5 +62,13 @@ Error InfoStreamBuilder::commit(const msf::MSFLayout &Layout,
if (auto EC = Writer.writeObject(H)) if (auto EC = Writer.writeObject(H))
return EC; return EC;
return NamedStreams.commit(Writer); if (auto EC = NamedStreams.commit(Writer))
return EC;
if (auto EC = Writer.writeInteger(0))
return EC;
for (auto E : Features) {
if (auto EC = Writer.writeEnum(E))
return EC;
}
return Error::success();
} }

View File

@ -71,6 +71,7 @@
; EMPTY-NEXT: Signature: 0x54E507E2 ; EMPTY-NEXT: Signature: 0x54E507E2
; EMPTY-NEXT: Age: 1 ; EMPTY-NEXT: Age: 1
; EMPTY-NEXT: Guid: {0B355641-86A0-A249-896F-9988FAE52FF0} ; EMPTY-NEXT: Guid: {0B355641-86A0-A249-896F-9988FAE52FF0}
; EMPTY-NEXT: Features: 0x1
; EMPTY-NEXT: Named Streams { ; EMPTY-NEXT: Named Streams {
; EMPTY-NEXT: /names: 13 ; EMPTY-NEXT: /names: 13
; EMPTY-NEXT: /LinkInfo: 5 ; EMPTY-NEXT: /LinkInfo: 5
@ -1003,6 +1004,7 @@
; ALL: Signature: 0x54E507E2 ; ALL: Signature: 0x54E507E2
; ALL: Age: 1 ; ALL: Age: 1
; ALL: Guid: {0B355641-86A0-A249-896F-9988FAE52FF0} ; ALL: Guid: {0B355641-86A0-A249-896F-9988FAE52FF0}
; ALL: Features: 0x1
; ALL: } ; ALL: }
; ALL: Type Info Stream (IPI) { ; ALL: Type Info Stream (IPI) {
; ALL: IPI Version: 20040203 ; ALL: IPI Version: 20040203
@ -1701,6 +1703,7 @@
; BIG-NEXT: Signature: 0x571FFE67 ; BIG-NEXT: Signature: 0x571FFE67
; BIG-NEXT: Age: 1 ; BIG-NEXT: Age: 1
; BIG-NEXT: Guid: {880ECC89-DF81-0B4F-839C-58CBD052E937} ; BIG-NEXT: Guid: {880ECC89-DF81-0B4F-839C-58CBD052E937}
; BIG-NEXT: Features: 0x1
; BIG-NEXT: Named Streams { ; BIG-NEXT: Named Streams {
; BIG-NEXT: /names: 13 ; BIG-NEXT: /names: 13
; BIG-NEXT: /LinkInfo: 5 ; BIG-NEXT: /LinkInfo: 5

View File

@ -27,6 +27,7 @@ CHECK-NEXT: Version: 20000404
CHECK-NEXT: Signature: 0x54E507E2 CHECK-NEXT: Signature: 0x54E507E2
CHECK-NEXT: Age: 1 CHECK-NEXT: Age: 1
CHECK-NEXT: Guid: {0B355641-86A0-A249-896F-9988FAE52FF0} CHECK-NEXT: Guid: {0B355641-86A0-A249-896F-9988FAE52FF0}
CHECK-NEXT: Features: 0x1
CHECK-NEXT: Named Streams { CHECK-NEXT: Named Streams {
CHECK: /names: CHECK: /names:
CHECK: } CHECK: }

View File

@ -44,6 +44,7 @@
; YAML-NEXT: Age: 1 ; YAML-NEXT: Age: 1
; YAML-NEXT: Guid: '{0B355641-86A0-A249-896F-9988FAE52FF0}' ; YAML-NEXT: Guid: '{0B355641-86A0-A249-896F-9988FAE52FF0}'
; YAML-NEXT: Signature: 1424295906 ; YAML-NEXT: Signature: 1424295906
; YAML-NEXT: Features: [ VC110 ]
; YAML-NEXT: Version: VC70 ; YAML-NEXT: Version: VC70
; YAML-NEXT: ... ; YAML-NEXT: ...

View File

@ -19,11 +19,34 @@
#include "llvm/DebugInfo/PDB/Native/StringTable.h" #include "llvm/DebugInfo/PDB/Native/StringTable.h"
#include "llvm/Support/FormatAdapters.h" #include "llvm/Support/FormatAdapters.h"
#include "llvm/Support/FormatProviders.h"
#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/FormatVariadic.h"
using namespace llvm; using namespace llvm;
using namespace llvm::pdb; using namespace llvm::pdb;
namespace llvm {
template <> struct format_provider<PdbRaw_FeatureSig> {
static void format(const PdbRaw_FeatureSig &Sig, raw_ostream &Stream,
StringRef Style) {
switch (Sig) {
case PdbRaw_FeatureSig::MinimalDebugInfo:
Stream << "MinimalDebugInfo";
break;
case PdbRaw_FeatureSig::NoTypeMerge:
Stream << "NoTypeMerge";
break;
case PdbRaw_FeatureSig::VC110:
Stream << "VC110";
break;
case PdbRaw_FeatureSig::VC140:
Stream << "VC140";
break;
}
}
};
}
template <typename R> using ValueOfRange = llvm::detail::ValueOfRange<R>; template <typename R> using ValueOfRange = llvm::detail::ValueOfRange<R>;
template <typename Range, typename Comp> template <typename Range, typename Comp>
@ -127,6 +150,22 @@ static bool diffAndPrint(StringRef Label, PDBFile &File1, PDBFile &File2, T V1,
return true; return true;
} }
template <typename T>
static bool diffAndPrint(StringRef Label, PDBFile &File1, PDBFile &File2,
ArrayRef<T> V1, ArrayRef<T> V2) {
if (V1 == V2) {
outs() << formatv(" {0}: No differences detected!\n", Label);
return false;
}
outs().indent(2) << Label << "\n";
outs().indent(4) << formatv("{0}: {1}\n", File1.getFilePath(),
make_range(V1.begin(), V1.end()));
outs().indent(4) << formatv("{0}: {1}\n", File2.getFilePath(),
make_range(V2.begin(), V2.end()));
return true;
}
template <typename T> template <typename T>
static bool printSymmetricDifferences(PDBFile &File1, PDBFile &File2, static bool printSymmetricDifferences(PDBFile &File1, PDBFile &File2,
T &&OnlyRange1, T &&OnlyRange2, T &&OnlyRange1, T &&OnlyRange2,
@ -446,6 +485,8 @@ Error DiffStyle::diffInfoStream() {
IS2.getSignature()); IS2.getSignature());
HasDiff |= HasDiff |=
diffAndPrint("Version", File1, File2, IS1.getVersion(), IS2.getVersion()); diffAndPrint("Version", File1, File2, IS1.getVersion(), IS2.getVersion());
HasDiff |= diffAndPrint("Features", File1, File2, IS1.getFeatureSignatures(),
IS2.getFeatureSignatures());
HasDiff |= diffAndPrint("Named Stream Byte Size", File1, File2, HasDiff |= diffAndPrint("Named Stream Byte Size", File1, File2,
IS1.getNamedStreamMapByteSize(), IS1.getNamedStreamMapByteSize(),
IS2.getNamedStreamMapByteSize()); IS2.getNamedStreamMapByteSize());

View File

@ -387,6 +387,7 @@ Error LLVMOutputStyle::dumpInfoStream() {
P.printHex("Signature", IS->getSignature()); P.printHex("Signature", IS->getSignature());
P.printNumber("Age", IS->getAge()); P.printNumber("Age", IS->getAge());
P.printObject("Guid", IS->getGuid()); P.printObject("Guid", IS->getGuid());
P.printHex("Features", IS->getFeatures());
{ {
DictScope DD(P, "Named Streams"); DictScope DD(P, "Named Streams");
for (const auto &S : IS->getNamedStreams().entries()) for (const auto &S : IS->getNamedStreams().entries())

View File

@ -38,6 +38,7 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbDbiModuleInfo)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbSymbolRecord) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbSymbolRecord)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbTpiRecord) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbTpiRecord)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::StreamBlockList) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::StreamBlockList)
LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::pdb::PdbRaw_FeatureSig)
namespace llvm { namespace llvm {
namespace yaml { namespace yaml {
@ -134,6 +135,16 @@ template <> struct ScalarEnumerationTraits<llvm::pdb::PdbRaw_TpiVer> {
io.enumCase(Value, "VC80", llvm::pdb::PdbRaw_TpiVer::PdbTpiV80); io.enumCase(Value, "VC80", llvm::pdb::PdbRaw_TpiVer::PdbTpiV80);
} }
}; };
template <> struct ScalarEnumerationTraits<llvm::pdb::PdbRaw_FeatureSig> {
static void enumeration(IO &io, PdbRaw_FeatureSig &Features) {
io.enumCase(Features, "MinimalDebugInfo",
PdbRaw_FeatureSig::MinimalDebugInfo);
io.enumCase(Features, "NoTypeMerge", PdbRaw_FeatureSig::NoTypeMerge);
io.enumCase(Features, "VC110", PdbRaw_FeatureSig::VC110);
io.enumCase(Features, "VC140", PdbRaw_FeatureSig::VC140);
}
};
} }
} }
@ -187,6 +198,7 @@ void MappingTraits<PdbInfoStream>::mapping(IO &IO, PdbInfoStream &Obj) {
IO.mapOptional("Age", Obj.Age, 1U); IO.mapOptional("Age", Obj.Age, 1U);
IO.mapOptional("Guid", Obj.Guid); IO.mapOptional("Guid", Obj.Guid);
IO.mapOptional("Signature", Obj.Signature, 0U); IO.mapOptional("Signature", Obj.Signature, 0U);
IO.mapOptional("Features", Obj.Features);
IO.mapOptional("Version", Obj.Version, PdbImplVC70); IO.mapOptional("Version", Obj.Version, PdbImplVC70);
} }

View File

@ -52,6 +52,7 @@ struct PdbInfoStream {
uint32_t Signature = 0; uint32_t Signature = 0;
uint32_t Age = 1; uint32_t Age = 1;
PDB_UniqueId Guid; PDB_UniqueId Guid;
std::vector<PdbRaw_FeatureSig> Features;
std::vector<NamedStreamMapping> NamedStreams; std::vector<NamedStreamMapping> NamedStreams;
}; };

View File

@ -145,6 +145,7 @@ Error YAMLOutputStyle::dumpPDBStream() {
Obj.PdbStream->Guid = InfoS.getGuid(); Obj.PdbStream->Guid = InfoS.getGuid();
Obj.PdbStream->Signature = InfoS.getSignature(); Obj.PdbStream->Signature = InfoS.getSignature();
Obj.PdbStream->Version = InfoS.getVersion(); Obj.PdbStream->Version = InfoS.getVersion();
Obj.PdbStream->Features = InfoS.getFeatureSignatures();
return Error::success(); return Error::success();
} }

View File

@ -404,6 +404,8 @@ static void yamlToPdb(StringRef Path) {
InfoBuilder.setGuid(Info.Guid); InfoBuilder.setGuid(Info.Guid);
InfoBuilder.setSignature(Info.Signature); InfoBuilder.setSignature(Info.Signature);
InfoBuilder.setVersion(Info.Version); InfoBuilder.setVersion(Info.Version);
for (auto F : Info.Features)
InfoBuilder.addFeature(F);
const auto &Dbi = YamlObj.DbiStream.getValueOr(DefaultDbiStream); const auto &Dbi = YamlObj.DbiStream.getValueOr(DefaultDbiStream);
auto &DbiBuilder = Builder.getDbiBuilder(); auto &DbiBuilder = Builder.getDbiBuilder();
@ -415,7 +417,7 @@ static void yamlToPdb(StringRef Path) {
DbiBuilder.setPdbDllVersion(Dbi.PdbDllVersion); DbiBuilder.setPdbDllVersion(Dbi.PdbDllVersion);
DbiBuilder.setVersionHeader(Dbi.VerHeader); DbiBuilder.setVersionHeader(Dbi.VerHeader);
for (const auto &MI : Dbi.ModInfos) { for (const auto &MI : Dbi.ModInfos) {
auto &ModiBuilder = ExitOnErr(DbiBuilder.addModuleInfo(MI.Obj)); auto &ModiBuilder = ExitOnErr(DbiBuilder.addModuleInfo(MI.Mod));
for (auto S : MI.SourceFiles) for (auto S : MI.SourceFiles)
ExitOnErr(DbiBuilder.addModuleSourceFile(MI.Mod, S)); ExitOnErr(DbiBuilder.addModuleSourceFile(MI.Mod, S));