From 05d5e6136f5a3f5de28ae64077200bbdc2cacfb4 Mon Sep 17 00:00:00 2001 From: Zachary Turner Date: Thu, 16 Mar 2017 20:19:11 +0000 Subject: [PATCH] [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 --- .../llvm/DebugInfo/PDB/Native/InfoStream.h | 7 ++++ .../DebugInfo/PDB/Native/InfoStreamBuilder.h | 2 + .../llvm/DebugInfo/PDB/Native/RawConstants.h | 16 ++++++++ llvm/lib/DebugInfo/PDB/Native/InfoStream.cpp | 30 ++++++++++++++ .../PDB/Native/InfoStreamBuilder.cpp | 17 +++++++- llvm/test/DebugInfo/PDB/pdbdump-headers.test | 3 ++ .../test/DebugInfo/PDB/pdbdump-readwrite.test | 1 + llvm/test/DebugInfo/PDB/pdbdump-yaml.test | 1 + llvm/tools/llvm-pdbdump/Diff.cpp | 41 +++++++++++++++++++ llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp | 1 + llvm/tools/llvm-pdbdump/PdbYaml.cpp | 12 ++++++ llvm/tools/llvm-pdbdump/PdbYaml.h | 1 + llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp | 1 + llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp | 4 +- 14 files changed, 134 insertions(+), 3 deletions(-) diff --git a/llvm/include/llvm/DebugInfo/PDB/Native/InfoStream.h b/llvm/include/llvm/DebugInfo/PDB/Native/InfoStream.h index 4a4222a680e6..1c38c2b6194f 100644 --- a/llvm/include/llvm/DebugInfo/PDB/Native/InfoStream.h +++ b/llvm/include/llvm/DebugInfo/PDB/Native/InfoStream.h @@ -10,6 +10,7 @@ #ifndef 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/DebugInfo/MSF/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Native/NamedStreamMap.h" @@ -40,6 +41,9 @@ public: PDB_UniqueId getGuid() const; uint32_t getNamedStreamMapByteSize() const; + PdbRaw_Features getFeatures() const; + ArrayRef getFeatureSignatures() const; + const NamedStreamMap &getNamedStreams() const; uint32_t getNamedStreamIndex(llvm::StringRef Name) const; @@ -66,6 +70,9 @@ private: // universally unique. PDB_UniqueId Guid; + std::vector FeatureSignatures; + PdbRaw_Features Features = PdbFeatureNone; + uint32_t NamedStreamMapByteSize = 0; NamedStreamMap NamedStreams; diff --git a/llvm/include/llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h b/llvm/include/llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h index 4133662615be..90c28a90d252 100644 --- a/llvm/include/llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h +++ b/llvm/include/llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h @@ -38,6 +38,7 @@ public: void setSignature(uint32_t S); void setAge(uint32_t A); void setGuid(PDB_UniqueId G); + void addFeature(PdbRaw_FeatureSig Sig); uint32_t finalize(); @@ -49,6 +50,7 @@ public: private: msf::MSFBuilder &Msf; + std::vector Features; PdbRaw_ImplVer Ver; uint32_t Sig; uint32_t Age; diff --git a/llvm/include/llvm/DebugInfo/PDB/Native/RawConstants.h b/llvm/include/llvm/DebugInfo/PDB/Native/RawConstants.h index af114ff52491..f5d4df8feb2e 100644 --- a/llvm/include/llvm/DebugInfo/PDB/Native/RawConstants.h +++ b/llvm/include/llvm/DebugInfo/PDB/Native/RawConstants.h @@ -10,6 +10,7 @@ #ifndef 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 @@ -32,6 +33,21 @@ enum PdbRaw_ImplVer : uint32_t { 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 { PdbDbiVC41 = 930803, PdbDbiV50 = 19960307, diff --git a/llvm/lib/DebugInfo/PDB/Native/InfoStream.cpp b/llvm/lib/DebugInfo/PDB/Native/InfoStream.cpp index 1ce0fe842065..0b223379b264 100644 --- a/llvm/lib/DebugInfo/PDB/Native/InfoStream.cpp +++ b/llvm/lib/DebugInfo/PDB/Native/InfoStream.cpp @@ -56,6 +56,30 @@ Error InfoStream::reload() { return EC; uint32_t NewOffset = Reader.getOffset(); 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(); } @@ -87,6 +111,12 @@ uint32_t InfoStream::getNamedStreamMapByteSize() const { return NamedStreamMapByteSize; } +PdbRaw_Features InfoStream::getFeatures() const { return Features; } + +ArrayRef InfoStream::getFeatureSignatures() const { + return FeatureSignatures; +} + const NamedStreamMap &InfoStream::getNamedStreams() const { return NamedStreams; } diff --git a/llvm/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp index f5b50a127db0..f019d410328a 100644 --- a/llvm/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp +++ b/llvm/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp @@ -36,8 +36,13 @@ void InfoStreamBuilder::setAge(uint32_t A) { Age = A; } void InfoStreamBuilder::setGuid(PDB_UniqueId G) { Guid = G; } +void InfoStreamBuilder::addFeature(PdbRaw_FeatureSig Sig) { + Features.push_back(Sig); +} + 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)) return EC; return Error::success(); @@ -57,5 +62,13 @@ Error InfoStreamBuilder::commit(const msf::MSFLayout &Layout, if (auto EC = Writer.writeObject(H)) 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(); } diff --git a/llvm/test/DebugInfo/PDB/pdbdump-headers.test b/llvm/test/DebugInfo/PDB/pdbdump-headers.test index 5fb3ad9220a0..c10d866f4a83 100644 --- a/llvm/test/DebugInfo/PDB/pdbdump-headers.test +++ b/llvm/test/DebugInfo/PDB/pdbdump-headers.test @@ -71,6 +71,7 @@ ; EMPTY-NEXT: Signature: 0x54E507E2 ; EMPTY-NEXT: Age: 1 ; EMPTY-NEXT: Guid: {0B355641-86A0-A249-896F-9988FAE52FF0} +; EMPTY-NEXT: Features: 0x1 ; EMPTY-NEXT: Named Streams { ; EMPTY-NEXT: /names: 13 ; EMPTY-NEXT: /LinkInfo: 5 @@ -1003,6 +1004,7 @@ ; ALL: Signature: 0x54E507E2 ; ALL: Age: 1 ; ALL: Guid: {0B355641-86A0-A249-896F-9988FAE52FF0} +; ALL: Features: 0x1 ; ALL: } ; ALL: Type Info Stream (IPI) { ; ALL: IPI Version: 20040203 @@ -1701,6 +1703,7 @@ ; BIG-NEXT: Signature: 0x571FFE67 ; BIG-NEXT: Age: 1 ; BIG-NEXT: Guid: {880ECC89-DF81-0B4F-839C-58CBD052E937} +; BIG-NEXT: Features: 0x1 ; BIG-NEXT: Named Streams { ; BIG-NEXT: /names: 13 ; BIG-NEXT: /LinkInfo: 5 diff --git a/llvm/test/DebugInfo/PDB/pdbdump-readwrite.test b/llvm/test/DebugInfo/PDB/pdbdump-readwrite.test index 780612aa65d7..4756faf68c2d 100644 --- a/llvm/test/DebugInfo/PDB/pdbdump-readwrite.test +++ b/llvm/test/DebugInfo/PDB/pdbdump-readwrite.test @@ -27,6 +27,7 @@ CHECK-NEXT: Version: 20000404 CHECK-NEXT: Signature: 0x54E507E2 CHECK-NEXT: Age: 1 CHECK-NEXT: Guid: {0B355641-86A0-A249-896F-9988FAE52FF0} +CHECK-NEXT: Features: 0x1 CHECK-NEXT: Named Streams { CHECK: /names: CHECK: } diff --git a/llvm/test/DebugInfo/PDB/pdbdump-yaml.test b/llvm/test/DebugInfo/PDB/pdbdump-yaml.test index e4cb5f5608be..44025be5bca7 100644 --- a/llvm/test/DebugInfo/PDB/pdbdump-yaml.test +++ b/llvm/test/DebugInfo/PDB/pdbdump-yaml.test @@ -44,6 +44,7 @@ ; YAML-NEXT: Age: 1 ; YAML-NEXT: Guid: '{0B355641-86A0-A249-896F-9988FAE52FF0}' ; YAML-NEXT: Signature: 1424295906 +; YAML-NEXT: Features: [ VC110 ] ; YAML-NEXT: Version: VC70 ; YAML-NEXT: ... diff --git a/llvm/tools/llvm-pdbdump/Diff.cpp b/llvm/tools/llvm-pdbdump/Diff.cpp index 529e57da5c1f..8c02d36044d8 100644 --- a/llvm/tools/llvm-pdbdump/Diff.cpp +++ b/llvm/tools/llvm-pdbdump/Diff.cpp @@ -19,11 +19,34 @@ #include "llvm/DebugInfo/PDB/Native/StringTable.h" #include "llvm/Support/FormatAdapters.h" +#include "llvm/Support/FormatProviders.h" #include "llvm/Support/FormatVariadic.h" using namespace llvm; using namespace llvm::pdb; +namespace llvm { +template <> struct format_provider { + 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 using ValueOfRange = llvm::detail::ValueOfRange; template @@ -127,6 +150,22 @@ static bool diffAndPrint(StringRef Label, PDBFile &File1, PDBFile &File2, T V1, return true; } +template +static bool diffAndPrint(StringRef Label, PDBFile &File1, PDBFile &File2, + ArrayRef V1, ArrayRef 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 static bool printSymmetricDifferences(PDBFile &File1, PDBFile &File2, T &&OnlyRange1, T &&OnlyRange2, @@ -446,6 +485,8 @@ Error DiffStyle::diffInfoStream() { IS2.getSignature()); HasDiff |= 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, IS1.getNamedStreamMapByteSize(), IS2.getNamedStreamMapByteSize()); diff --git a/llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp b/llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp index 04a9c41e47ba..d94b398e580c 100644 --- a/llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp +++ b/llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp @@ -387,6 +387,7 @@ Error LLVMOutputStyle::dumpInfoStream() { P.printHex("Signature", IS->getSignature()); P.printNumber("Age", IS->getAge()); P.printObject("Guid", IS->getGuid()); + P.printHex("Features", IS->getFeatures()); { DictScope DD(P, "Named Streams"); for (const auto &S : IS->getNamedStreams().entries()) diff --git a/llvm/tools/llvm-pdbdump/PdbYaml.cpp b/llvm/tools/llvm-pdbdump/PdbYaml.cpp index 21f5a775c55a..e2c4ee967ed3 100644 --- a/llvm/tools/llvm-pdbdump/PdbYaml.cpp +++ b/llvm/tools/llvm-pdbdump/PdbYaml.cpp @@ -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::PdbTpiRecord) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::StreamBlockList) +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::pdb::PdbRaw_FeatureSig) namespace llvm { namespace yaml { @@ -134,6 +135,16 @@ template <> struct ScalarEnumerationTraits { io.enumCase(Value, "VC80", llvm::pdb::PdbRaw_TpiVer::PdbTpiV80); } }; + +template <> struct ScalarEnumerationTraits { + 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::mapping(IO &IO, PdbInfoStream &Obj) { IO.mapOptional("Age", Obj.Age, 1U); IO.mapOptional("Guid", Obj.Guid); IO.mapOptional("Signature", Obj.Signature, 0U); + IO.mapOptional("Features", Obj.Features); IO.mapOptional("Version", Obj.Version, PdbImplVC70); } diff --git a/llvm/tools/llvm-pdbdump/PdbYaml.h b/llvm/tools/llvm-pdbdump/PdbYaml.h index 7632d7e0b605..2c4cd237f8d7 100644 --- a/llvm/tools/llvm-pdbdump/PdbYaml.h +++ b/llvm/tools/llvm-pdbdump/PdbYaml.h @@ -52,6 +52,7 @@ struct PdbInfoStream { uint32_t Signature = 0; uint32_t Age = 1; PDB_UniqueId Guid; + std::vector Features; std::vector NamedStreams; }; diff --git a/llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp b/llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp index fab3760fabb2..5b53d2137166 100644 --- a/llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp +++ b/llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp @@ -145,6 +145,7 @@ Error YAMLOutputStyle::dumpPDBStream() { Obj.PdbStream->Guid = InfoS.getGuid(); Obj.PdbStream->Signature = InfoS.getSignature(); Obj.PdbStream->Version = InfoS.getVersion(); + Obj.PdbStream->Features = InfoS.getFeatureSignatures(); return Error::success(); } diff --git a/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp b/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp index 7dd4eec1fe5b..8b166411f0bf 100644 --- a/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp +++ b/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -404,6 +404,8 @@ static void yamlToPdb(StringRef Path) { InfoBuilder.setGuid(Info.Guid); InfoBuilder.setSignature(Info.Signature); InfoBuilder.setVersion(Info.Version); + for (auto F : Info.Features) + InfoBuilder.addFeature(F); const auto &Dbi = YamlObj.DbiStream.getValueOr(DefaultDbiStream); auto &DbiBuilder = Builder.getDbiBuilder(); @@ -415,7 +417,7 @@ static void yamlToPdb(StringRef Path) { DbiBuilder.setPdbDllVersion(Dbi.PdbDllVersion); DbiBuilder.setVersionHeader(Dbi.VerHeader); 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) ExitOnErr(DbiBuilder.addModuleSourceFile(MI.Mod, S));