void reset(ArrayRef<uint8_t> 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;
#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"
codeview::LazyRandomTypeCollection &typeCollection() { return *Types; }
+ BinarySubstreamRef getTypeRecordsSubstream() const;
+
Error commit();
private:
std::unique_ptr<codeview::LazyRandomTypeCollection> Types;
+ BinarySubstreamRef TypeRecordsSubstream;
+
codeview::CVTypeArray TypeRecords;
std::unique_ptr<BinaryStream> HashStream;
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; }
};
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));
"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.
uint32_t TpiStream::getNumHashBuckets() const { return Header->NumHashBuckets; }
uint32_t TpiStream::getHashKeySize() const { return Header->HashKeySize; }
+BinarySubstreamRef TpiStream::getTypeRecordsSubstream() const {
+ return TypeRecordsSubstream;
+}
+
FixedStreamArray<support::ulittle32_t> TpiStream::getHashValues() const {
return HashValues;
}
--- /dev/null
+; 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
#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;
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();
}
P.formatMsfStreamData("Edit and Continue Data", File, Layout, NS);
}
+void BytesOutputStyle::dumpTypeIndex(uint32_t StreamIdx,
+ ArrayRef<uint32_t> 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");
P.formatBinary("Bytes", Data, Min);
}
+Expected<codeview::LazyRandomTypeCollection &>
+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<LazyRandomTypeCollection>(Types, Count, Offsets);
+
+ return *TypeCollection;
+}
+
void BytesOutputStyle::dumpStreamBytes() {
if (StreamPurposes.empty())
discoverStreamPurposes(File, StreamPurposes);
namespace llvm {
+namespace codeview {
+class LazyRandomTypeCollection;
+}
+
namespace pdb {
class PDBFile;
void dumpTypeServerMap();
void dumpECData();
+ void dumpTypeIndex(uint32_t StreamIdx, ArrayRef<uint32_t> Indices);
+
+ Expected<codeview::LazyRandomTypeCollection &>
+ initializeTypes(uint32_t StreamIdx);
+
+ std::unique_ptr<codeview::LazyRandomTypeCollection> TpiTypes;
+ std::unique_ptr<codeview::LazyRandomTypeCollection> IpiTypes;
+
PDBFile &File;
LinePrinter P;
ExitOnError Err;
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<NumberRange> DumpBlockRange;
llvm::Optional<NumberRange> DumpByteRange;
cl::opt<bool> ECData("ec", cl::desc("Dump edit and continue map"),
cl::sub(BytesSubcommand), cl::cat(DbiBytes));
+cl::list<uint32_t>
+ 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<uint32_t>
+ 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<std::string> InputFilenames(cl::Positional,
cl::desc("<input PDB files>"),
cl::OneOrMore, cl::sub(BytesSubcommand));
extern llvm::cl::opt<bool> TypeServerMap;
extern llvm::cl::opt<bool> ECData;
+extern llvm::cl::list<uint32_t> TypeIndex;
+extern llvm::cl::list<uint32_t> IdIndex;
+
} // namespace bytes
namespace dump {