diff --git a/llvm/include/llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h b/llvm/include/llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h index 3c678d6169ce..8b1540abf903 100644 --- a/llvm/include/llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h +++ b/llvm/include/llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h @@ -61,6 +61,8 @@ public: void reset(ArrayRef Data, uint32_t RecordCountHint); void reset(StringRef Data, uint32_t RecordCountHint); + uint32_t getOffsetOfType(TypeIndex Index); + CVType getType(TypeIndex Index) override; StringRef getTypeName(TypeIndex Index) override; bool contains(TypeIndex Index) override; diff --git a/llvm/include/llvm/DebugInfo/PDB/Native/TpiStream.h b/llvm/include/llvm/DebugInfo/PDB/Native/TpiStream.h index 0ee697696ca5..d3475205a6c2 100644 --- a/llvm/include/llvm/DebugInfo/PDB/Native/TpiStream.h +++ b/llvm/include/llvm/DebugInfo/PDB/Native/TpiStream.h @@ -16,6 +16,7 @@ #include "llvm/DebugInfo/PDB/Native/RawTypes.h" #include "llvm/DebugInfo/PDB/PDBTypes.h" #include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Error.h" @@ -57,6 +58,8 @@ public: codeview::LazyRandomTypeCollection &typeCollection() { return *Types; } + BinarySubstreamRef getTypeRecordsSubstream() const; + Error commit(); private: @@ -65,6 +68,8 @@ private: std::unique_ptr Types; + BinarySubstreamRef TypeRecordsSubstream; + codeview::CVTypeArray TypeRecords; std::unique_ptr HashStream; diff --git a/llvm/include/llvm/Support/BinaryStreamRef.h b/llvm/include/llvm/Support/BinaryStreamRef.h index f288a2cb70be..499d91cfb11c 100644 --- a/llvm/include/llvm/Support/BinaryStreamRef.h +++ b/llvm/include/llvm/Support/BinaryStreamRef.h @@ -170,6 +170,10 @@ struct BinarySubstreamRef { uint32_t Offset; // Offset in the parent stream BinaryStreamRef StreamData; // Stream Data + BinarySubstreamRef slice(uint32_t Off, uint32_t Size) const { + BinaryStreamRef SubSub = StreamData.slice(Off, Size); + return {Off + Offset, SubSub}; + } uint32_t size() const { return StreamData.getLength(); } bool empty() const { return size() == 0; } }; diff --git a/llvm/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp b/llvm/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp index f06d9c843116..20f7e72c3af3 100644 --- a/llvm/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp +++ b/llvm/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp @@ -67,6 +67,13 @@ void LazyRandomTypeCollection::reset(ArrayRef Data, reset(toStringRef(Data), RecordCountHint); } +uint32_t LazyRandomTypeCollection::getOffsetOfType(TypeIndex Index) { + error(ensureTypeExists(Index)); + assert(contains(Index)); + + return Records[Index.toArrayIndex()].Offset; +} + CVType LazyRandomTypeCollection::getType(TypeIndex Index) { error(ensureTypeExists(Index)); assert(contains(Index)); diff --git a/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp b/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp index 67c803d3124e..f917ef91f639 100644 --- a/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp +++ b/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp @@ -66,7 +66,13 @@ Error TpiStream::reload() { "TPI Stream Invalid number of hash buckets."); // The actual type records themselves come from this stream - if (auto EC = Reader.readArray(TypeRecords, Header->TypeRecordBytes)) + if (auto EC = + Reader.readSubstream(TypeRecordsSubstream, Header->TypeRecordBytes)) + return EC; + + BinaryStreamReader RecordReader(TypeRecordsSubstream.StreamData); + if (auto EC = + RecordReader.readArray(TypeRecords, TypeRecordsSubstream.size())) return EC; // Hash indices, hash values, etc come from the hash stream. @@ -135,6 +141,10 @@ uint16_t TpiStream::getTypeHashStreamAuxIndex() const { uint32_t TpiStream::getNumHashBuckets() const { return Header->NumHashBuckets; } uint32_t TpiStream::getHashKeySize() const { return Header->HashKeySize; } +BinarySubstreamRef TpiStream::getTypeRecordsSubstream() const { + return TypeRecordsSubstream; +} + FixedStreamArray TpiStream::getHashValues() const { return HashValues; } diff --git a/llvm/test/DebugInfo/PDB/tpi-bytes.test b/llvm/test/DebugInfo/PDB/tpi-bytes.test new file mode 100644 index 000000000000..2345d3aa21ba --- /dev/null +++ b/llvm/test/DebugInfo/PDB/tpi-bytes.test @@ -0,0 +1,27 @@ +; RUN: llvm-pdbutil bytes -type=0x1002 %p/Inputs/empty.pdb | FileCheck --check-prefix=TYPE %s +; RUN: llvm-pdbutil bytes -id=0x1007 %p/Inputs/empty.pdb | FileCheck --check-prefix=ID %s +; RUN: llvm-pdbutil bytes -type=0x2000 %p/Inputs/empty.pdb | FileCheck --check-prefix=INVALID-TYPE %s +; RUN: llvm-pdbutil bytes -id=0x2000 %p/Inputs/empty.pdb | FileCheck --check-prefix=INVALID-ID %s + +TYPE: Type (TPI) Records +TYPE-NEXT: ============================================================ +TYPE-NEXT: Type 0x1002 ( +TYPE-NEXT: 12050: 4A000312 02150300 01006170 6172746D 656E7400 02150300 02007369 6E676C65 |J.........apartment.......single| +TYPE-NEXT: 12070: 00F3F2F1 02150300 03006672 656500F1 02150300 04006E65 75747261 6C00F2F1 |..........free........neutral...| +TYPE-NEXT: 12090: 02150300 0500626F 746800F1 |......both..| +TYPE-NEXT: ) + +ID: Index (IPI) Records +ID-NEXT: ============================================================ +ID-NEXT: Type 0x1007 ( +ID-NEXT: 140C4: 2E000516 00000000 643A5C73 72635C6C 6C766D5C 74657374 5C446562 7567496E |........d:\src\llvm\test\DebugIn| +ID-NEXT: 140E4: 666F5C50 44425C49 6E707574 7300F2F1 |fo\PDB\Inputs...| +ID-NEXT: ) + +INVALID-TYPE: Type (TPI) Records +INVALID-TYPE-NEXT: ============================================================ +INVALID-TYPE-NEXT: Error: TypeIndex 0x2000 does not exist + +INVALID-ID: Index (IPI) Records +INVALID-ID-NEXT: ============================================================ +INVALID-ID-NEXT: Error: TypeIndex 0x2000 does not exist diff --git a/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp b/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp index 166136affed1..288bef721041 100644 --- a/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp +++ b/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp @@ -12,16 +12,20 @@ #include "StreamUtil.h" #include "llvm-pdbutil.h" +#include "llvm/DebugInfo/CodeView/Formatters.h" +#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Native/DbiStream.h" #include "llvm/DebugInfo/PDB/Native/InfoStream.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" #include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/FormatAdapters.h" #include "llvm/Support/FormatVariadic.h" using namespace llvm; +using namespace llvm::codeview; using namespace llvm::msf; using namespace llvm::pdb; @@ -154,6 +158,16 @@ Error BytesOutputStyle::dump() { P.NewLine(); } + if (!opts::bytes::TypeIndex.empty()) { + dumpTypeIndex(StreamTPI, opts::bytes::TypeIndex); + P.NewLine(); + } + + if (!opts::bytes::IdIndex.empty()) { + dumpTypeIndex(StreamIPI, opts::bytes::IdIndex); + P.NewLine(); + } + return Error::success(); } @@ -253,6 +267,36 @@ void BytesOutputStyle::dumpECData() { P.formatMsfStreamData("Edit and Continue Data", File, Layout, NS); } +void BytesOutputStyle::dumpTypeIndex(uint32_t StreamIdx, + ArrayRef Indices) { + assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI); + assert(!Indices.empty()); + + bool IsTpi = (StreamIdx == StreamTPI); + + StringRef Label = IsTpi ? "Type (TPI) Records" : "Index (IPI) Records"; + printHeader(P, Label); + auto &Stream = Err(IsTpi ? File.getPDBTpiStream() : File.getPDBIpiStream()); + + AutoIndent Indent(P); + + auto Substream = Stream.getTypeRecordsSubstream(); + auto &Types = Err(initializeTypes(StreamIdx)); + auto Layout = File.getStreamLayout(StreamIdx); + for (const auto &Id : Indices) { + TypeIndex TI(Id); + if (TI.toArrayIndex() >= Types.capacity()) { + P.formatLine("Error: TypeIndex {0} does not exist", TI); + continue; + } + + auto Type = Types.getType(TI); + uint32_t Offset = Types.getOffsetOfType(TI); + auto OneType = Substream.slice(Offset, Type.length()); + P.formatMsfStreamData(formatv("Type {0}", TI).str(), File, Layout, OneType); + } +} + void BytesOutputStyle::dumpByteRanges(uint32_t Min, uint32_t Max) { printHeader(P, "MSF Bytes"); @@ -268,6 +312,26 @@ void BytesOutputStyle::dumpByteRanges(uint32_t Min, uint32_t Max) { P.formatBinary("Bytes", Data, Min); } +Expected +BytesOutputStyle::initializeTypes(uint32_t StreamIdx) { + auto &TypeCollection = (StreamIdx == StreamTPI) ? TpiTypes : IpiTypes; + if (TypeCollection) + return *TypeCollection; + + auto Tpi = (StreamIdx == StreamTPI) ? File.getPDBTpiStream() + : File.getPDBIpiStream(); + if (!Tpi) + return Tpi.takeError(); + + auto &Types = Tpi->typeArray(); + uint32_t Count = Tpi->getNumTypeRecords(); + auto Offsets = Tpi->getTypeIndexOffsets(); + TypeCollection = + llvm::make_unique(Types, Count, Offsets); + + return *TypeCollection; +} + void BytesOutputStyle::dumpStreamBytes() { if (StreamPurposes.empty()) discoverStreamPurposes(File, StreamPurposes); diff --git a/llvm/tools/llvm-pdbutil/BytesOutputStyle.h b/llvm/tools/llvm-pdbutil/BytesOutputStyle.h index 0895ee6532a0..af7e636c6b26 100644 --- a/llvm/tools/llvm-pdbutil/BytesOutputStyle.h +++ b/llvm/tools/llvm-pdbutil/BytesOutputStyle.h @@ -17,6 +17,10 @@ namespace llvm { +namespace codeview { +class LazyRandomTypeCollection; +} + namespace pdb { class PDBFile; @@ -40,6 +44,14 @@ private: void dumpTypeServerMap(); void dumpECData(); + void dumpTypeIndex(uint32_t StreamIdx, ArrayRef Indices); + + Expected + initializeTypes(uint32_t StreamIdx); + + std::unique_ptr TpiTypes; + std::unique_ptr IpiTypes; + PDBFile &File; LinePrinter P; ExitOnError Err; diff --git a/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp b/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp index 48dabc8a57af..0586b6b5c4ad 100644 --- a/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp +++ b/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp @@ -270,6 +270,7 @@ namespace bytes { cl::OptionCategory MsfBytes("MSF File Options"); cl::OptionCategory DbiBytes("Dbi Stream Options"); cl::OptionCategory PdbBytes("PDB Stream Options"); +cl::OptionCategory Types("Type Options"); llvm::Optional DumpBlockRange; llvm::Optional DumpByteRange; @@ -306,6 +307,16 @@ cl::opt TypeServerMap("type-server", cl::desc("Dump type server map"), cl::opt ECData("ec", cl::desc("Dump edit and continue map"), cl::sub(BytesSubcommand), cl::cat(DbiBytes)); +cl::list + TypeIndex("type", + cl::desc("Dump the type record with the given type index"), + cl::ZeroOrMore, cl::CommaSeparated, cl::sub(BytesSubcommand), + cl::cat(TypeCategory)); +cl::list + IdIndex("id", cl::desc("Dump the id record with the given type index"), + cl::ZeroOrMore, cl::CommaSeparated, cl::sub(BytesSubcommand), + cl::cat(TypeCategory)); + cl::list InputFilenames(cl::Positional, cl::desc(""), cl::OneOrMore, cl::sub(BytesSubcommand)); diff --git a/llvm/tools/llvm-pdbutil/llvm-pdbutil.h b/llvm/tools/llvm-pdbutil/llvm-pdbutil.h index b7fedd3ae439..67baf24c58df 100644 --- a/llvm/tools/llvm-pdbutil/llvm-pdbutil.h +++ b/llvm/tools/llvm-pdbutil/llvm-pdbutil.h @@ -110,6 +110,9 @@ extern llvm::cl::opt FileInfo; extern llvm::cl::opt TypeServerMap; extern llvm::cl::opt ECData; +extern llvm::cl::list TypeIndex; +extern llvm::cl::list IdIndex; + } // namespace bytes namespace dump {