summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h1
-rw-r--r--include/llvm/DebugInfo/CodeView/TypeHashing.h55
-rw-r--r--lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp14
-rw-r--r--test/DebugInfo/PDB/Inputs/obj-hashes-1.yaml50
-rw-r--r--test/DebugInfo/PDB/Inputs/obj-hashes-2.yaml55
-rw-r--r--test/DebugInfo/PDB/obj-globalhash.test54
-rw-r--r--tools/llvm-pdbutil/DumpOutputStyle.cpp101
-rw-r--r--tools/llvm-pdbutil/DumpOutputStyle.h1
-rw-r--r--tools/llvm-readobj/COFFDumper.cpp1
9 files changed, 304 insertions, 28 deletions
diff --git a/include/llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h b/include/llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h
index 1d5117475bb..16d78692c83 100644
--- a/include/llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h
+++ b/include/llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h
@@ -67,6 +67,7 @@ public:
void reset(ArrayRef<uint8_t> Data, uint32_t RecordCountHint);
void reset(StringRef Data, uint32_t RecordCountHint);
+ void reset(BinaryStreamReader &Reader, uint32_t RecordCountHint);
uint32_t getOffsetOfType(TypeIndex Index);
diff --git a/include/llvm/DebugInfo/CodeView/TypeHashing.h b/include/llvm/DebugInfo/CodeView/TypeHashing.h
index 8f7d2abadca..4032bee1044 100644
--- a/include/llvm/DebugInfo/CodeView/TypeHashing.h
+++ b/include/llvm/DebugInfo/CodeView/TypeHashing.h
@@ -10,11 +10,14 @@
#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPEHASHING_H
#define LLVM_DEBUGINFO_CODEVIEW_TYPEHASHING_H
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/ADT/Hashing.h"
+
#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/TypeCollection.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
-#include "llvm/ADT/DenseMapInfo.h"
-#include "llvm/ADT/Hashing.h"
+#include "llvm/Support/FormatProviders.h"
namespace llvm {
namespace codeview {
@@ -29,7 +32,28 @@ struct LocallyHashedType {
hash_code Hash;
ArrayRef<uint8_t> RecordData;
+ /// Given a type, compute its local hash.
static LocallyHashedType hashType(ArrayRef<uint8_t> RecordData);
+
+ /// Given a sequence of types, compute all of the local hashes.
+ template <typename Range>
+ static std::vector<LocallyHashedType> hashTypes(Range &&Records) {
+ std::vector<LocallyHashedType> Hashes;
+ Hashes.reserve(std::distance(std::begin(Records), std::end(Records)));
+ for (const auto &R : Records)
+ Hashes.push_back(hashType(R));
+
+ return Hashes;
+ }
+
+ static std::vector<LocallyHashedType>
+ hashTypeCollection(TypeCollection &Types) {
+ std::vector<LocallyHashedType> Hashes;
+ Types.ForEachRecord([&Hashes](TypeIndex TI, const CVType &Type) {
+ Hashes.push_back(hashType(Type.RecordData));
+ });
+ return Hashes;
+ }
};
/// A globally hashed type represents a hash value that is sufficient to
@@ -73,6 +97,15 @@ struct GloballyHashedType {
return Hashes;
}
+
+ static std::vector<GloballyHashedType>
+ hashTypeCollection(TypeCollection &Types) {
+ std::vector<GloballyHashedType> Hashes;
+ Types.ForEachRecord([&Hashes](TypeIndex TI, const CVType &Type) {
+ Hashes.push_back(hashType(Type.RecordData, Hashes, Hashes));
+ });
+ return Hashes;
+ }
};
} // namespace codeview
@@ -114,6 +147,24 @@ template <> struct DenseMapInfo<codeview::GloballyHashedType> {
}
};
+template <> struct format_provider<codeview::LocallyHashedType> {
+public:
+ static void format(const codeview::LocallyHashedType &V,
+ llvm::raw_ostream &Stream, StringRef Style) {
+ write_hex(Stream, V.Hash, HexPrintStyle::Upper, 8);
+ }
+};
+
+template <> struct format_provider<codeview::GloballyHashedType> {
+public:
+ static void format(const codeview::GloballyHashedType &V,
+ llvm::raw_ostream &Stream, StringRef Style) {
+ for (uint8_t B : V.Hash) {
+ write_hex(Stream, B, HexPrintStyle::Upper, 2);
+ }
+ }
+};
+
} // namespace llvm
#endif
diff --git a/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp b/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp
index bad291e8381..ca8007411ca 100644
--- a/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp
+++ b/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp
@@ -58,21 +58,27 @@ LazyRandomTypeCollection::LazyRandomTypeCollection(const CVTypeArray &Types,
uint32_t NumRecords)
: LazyRandomTypeCollection(Types, NumRecords, PartialOffsetArray()) {}
-void LazyRandomTypeCollection::reset(StringRef Data, uint32_t RecordCountHint) {
+void LazyRandomTypeCollection::reset(BinaryStreamReader &Reader,
+ uint32_t RecordCountHint) {
Count = 0;
PartialOffsets = PartialOffsetArray();
- BinaryStreamReader Reader(Data, support::little);
- error(Reader.readArray(Types, Reader.getLength()));
+ error(Reader.readArray(Types, Reader.bytesRemaining()));
// Clear and then resize, to make sure existing data gets destroyed.
Records.clear();
Records.resize(RecordCountHint);
}
+void LazyRandomTypeCollection::reset(StringRef Data, uint32_t RecordCountHint) {
+ BinaryStreamReader Reader(Data, support::little);
+ reset(Reader, RecordCountHint);
+}
+
void LazyRandomTypeCollection::reset(ArrayRef<uint8_t> Data,
uint32_t RecordCountHint) {
- reset(toStringRef(Data), RecordCountHint);
+ BinaryStreamReader Reader(Data, support::little);
+ reset(Reader, RecordCountHint);
}
uint32_t LazyRandomTypeCollection::getOffsetOfType(TypeIndex Index) {
diff --git a/test/DebugInfo/PDB/Inputs/obj-hashes-1.yaml b/test/DebugInfo/PDB/Inputs/obj-hashes-1.yaml
new file mode 100644
index 00000000000..80d7b3c87b6
--- /dev/null
+++ b/test/DebugInfo/PDB/Inputs/obj-hashes-1.yaml
@@ -0,0 +1,50 @@
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: '.debug$T'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ Types:
+ # char**
+ - Kind: LF_POINTER
+ Pointer:
+ ReferentType: 272
+ Attrs: 32778
+ # int**
+ - Kind: LF_POINTER
+ Pointer:
+ ReferentType: 372
+ Attrs: 32778
+ # int***
+ - Kind: LF_POINTER
+ Pointer:
+ ReferentType: 4097
+ Attrs: 32778
+ # (char**, int***)
+ - Kind: LF_ARGLIST
+ ArgList:
+ ArgIndices: [ 4096, 4098 ]
+ # int** (char**, int***)
+ - Kind: LF_PROCEDURE
+ Procedure:
+ ReturnType: 4097
+ CallConv: NearC
+ Options: [ None ]
+ ParameterCount: 2
+ ArgumentList: 4099
+symbols:
+ - Name: '.debug$T'
+ Value: 0
+ SectionNumber: 6
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 68
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 2189213922
+ Number: 6
+...
diff --git a/test/DebugInfo/PDB/Inputs/obj-hashes-2.yaml b/test/DebugInfo/PDB/Inputs/obj-hashes-2.yaml
new file mode 100644
index 00000000000..1c0aa2cc175
--- /dev/null
+++ b/test/DebugInfo/PDB/Inputs/obj-hashes-2.yaml
@@ -0,0 +1,55 @@
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: '.debug$T'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ Types:
+ # int**
+ - Kind: LF_POINTER
+ Pointer:
+ ReferentType: 372
+ Attrs: 32778
+ # int***
+ - Kind: LF_POINTER
+ Pointer:
+ ReferentType: 4096
+ Attrs: 32778
+ # char**
+ - Kind: LF_POINTER
+ Pointer:
+ ReferentType: 272
+ Attrs: 32778
+ # double**
+ - Kind: LF_POINTER
+ Pointer:
+ ReferentType: 321
+ Attrs: 32778
+ # (char**, int***)
+ - Kind: LF_ARGLIST
+ ArgList:
+ ArgIndices: [ 4098, 4097 ]
+ # int** (char**, int***)
+ - Kind: LF_PROCEDURE
+ Procedure:
+ ReturnType: 4096
+ CallConv: NearC
+ Options: [ None ]
+ ParameterCount: 2
+ ArgumentList: 4100
+symbols:
+ - Name: '.debug$T'
+ Value: 0
+ SectionNumber: 6
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 68
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 2189213922
+ Number: 6
+...
diff --git a/test/DebugInfo/PDB/obj-globalhash.test b/test/DebugInfo/PDB/obj-globalhash.test
new file mode 100644
index 00000000000..629192905a4
--- /dev/null
+++ b/test/DebugInfo/PDB/obj-globalhash.test
@@ -0,0 +1,54 @@
+RUN: yaml2obj %p/Inputs/obj-hashes-1.yaml > %T/obj-hashes-1.obj
+RUN: yaml2obj %p/Inputs/obj-hashes-2.yaml > %T/obj-hashes-2.obj
+RUN: echo obj-hashes-1 > %T/hashes-combined.out
+RUN: llvm-pdbutil dump -type-extras %T/obj-hashes-1.obj >> %T/hashes-combined.out
+RUN: echo obj-hashes-2 >> %T/hashes-combined.out
+RUN: llvm-pdbutil dump -type-extras %T/obj-hashes-2.obj >> %T/hashes-combined.out
+RUN: cat %T/hashes-combined.out | FileCheck --check-prefix=CHECK-ONE %s
+RUN: cat %T/hashes-combined.out | FileCheck --check-prefix=CHECK-TWO %s
+RUN: cat %T/hashes-combined.out | FileCheck --check-prefix=CHECK-THREE %s
+RUN: cat %T/hashes-combined.out | FileCheck --check-prefix=CHECK-FOUR %s
+RUN: cat %T/hashes-combined.out | FileCheck --check-prefix=CHECK-FIVE %s
+RUN: cat %T/hashes-combined.out | FileCheck --check-prefix=CHECK-SIX %s
+
+; char**. Both the local and global hashes should be the same, since the only
+; back-references are for simple types which have fixed indices.
+CHECK-ONE: obj-hashes-1
+CHECK-ONE: TI: 0x1001, LocalHash: 8C051421, GlobalHash: 8B2BA87CC27BF9D290A31A6070FA296AAA577E53
+CHECK-ONE: obj-hashes-2
+CHECK-ONE: TI: 0x1000, LocalHash: 8C051421, GlobalHash: 8B2BA87CC27BF9D290A31A6070FA296AAA577E53
+
+; int**. Same as char**, both the local and global hashes should be the same.
+CHECK-TWO: obj-hashes-1
+CHECK-TWO: TI: 0x1000, LocalHash: 8A50855E, GlobalHash: 1522A98D88FAF71B618D97BCAC2B89A424EC4805
+CHECK-TWO: obj-hashes-2
+CHECK-TWO: TI: 0x1002, LocalHash: 8A50855E, GlobalHash: 1522A98D88FAF71B618D97BCAC2B89A424EC4805
+
+; int***. Different local hashes, since the referent type (int**) is not at the
+; same TypeIndex in both streams. Same global hash, since they represent the
+; same record.
+CHECK-THREE: obj-hashes-1
+CHECK-THREE: TI: 0x1002, LocalHash: C1B0E34B, GlobalHash: EC11CE9F78D6BF61F8D913A9E2C98293782A7EB4
+CHECK-THREE: obj-hashes-2
+CHECK-THREE: TI: 0x1001, LocalHash: 813E462C, GlobalHash: EC11CE9F78D6BF61F8D913A9E2C98293782A7EB4
+
+; arg list (char**, int***). Different local hashes, since the parameter types
+; both occur at different TypeIndices in their respective input streams. Same
+; global hash, since the global hash of all referenced types is the same in
+; both streams.
+CHECK-FOUR: obj-hashes-1
+CHECK-FOUR: TI: 0x1003, LocalHash: F9B7D117, GlobalHash: 1088AD64CEBC88D9E015058A159516AF20B79286
+CHECK-FOUR: obj-hashes-2
+CHECK-FOUR: TI: 0x1004, LocalHash: 29800A81, GlobalHash: 1088AD64CEBC88D9E015058A159516AF20B79286
+
+; double**. This is only in stream 2, as a means to throw off the indexing.
+CHECK-FIVE: obj-hashes-1
+CHECK-FIVE: obj-hashes-2
+CHECK-FIVE: TI: 0x1003, LocalHash: A8EEF56D, GlobalHash: 7803BBDB2947EF46BEA2310D102BD08F68315506
+
+; int** (char**, int***). For the same logic as described in previous records,
+; these two records have the same global hash but different local hashes.
+CHECK-SIX: obj-hashes-1
+CHECK-SIX: TI: 0x1004, LocalHash: 25FFC8CB, GlobalHash: 457ABCB8AB70407594B5D72BF471B6BDECC99BC9
+CHECK-SIX: obj-hashes-2
+CHECK-SIX: TI: 0x1005, LocalHash: F34B0F86, GlobalHash: 457ABCB8AB70407594B5D72BF471B6BDECC99BC9
diff --git a/tools/llvm-pdbutil/DumpOutputStyle.cpp b/tools/llvm-pdbutil/DumpOutputStyle.cpp
index 5b02d68bc7a..84355e7bd2e 100644
--- a/tools/llvm-pdbutil/DumpOutputStyle.cpp
+++ b/tools/llvm-pdbutil/DumpOutputStyle.cpp
@@ -38,6 +38,7 @@
#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h"
#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h"
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
+#include "llvm/DebugInfo/CodeView/TypeHashing.h"
#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
@@ -50,8 +51,8 @@
#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
#include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
-#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
#include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
#include "llvm/DebugInfo/PDB/PDBExtras.h"
@@ -135,16 +136,23 @@ Error DumpOutputStyle::dump() {
return EC;
}
- if (opts::dump::DumpTypes || !opts::dump::DumpTypeIndex.empty() ||
- opts::dump::DumpTypeExtras) {
- if (auto EC = dumpTpiStream(StreamTPI))
- return EC;
- }
+ if (File.isObj()) {
+ if (opts::dump::DumpTypes || !opts::dump::DumpTypeIndex.empty() ||
+ opts::dump::DumpTypeExtras)
+ if (auto EC = dumpTypesFromObjectFile())
+ return EC;
+ } else {
+ if (opts::dump::DumpTypes || !opts::dump::DumpTypeIndex.empty() ||
+ opts::dump::DumpTypeExtras) {
+ if (auto EC = dumpTpiStream(StreamTPI))
+ return EC;
+ }
- if (opts::dump::DumpIds || !opts::dump::DumpIdIndex.empty() ||
- opts::dump::DumpIdExtras) {
- if (auto EC = dumpTpiStream(StreamIPI))
- return EC;
+ if (opts::dump::DumpIds || !opts::dump::DumpIdIndex.empty() ||
+ opts::dump::DumpIdExtras) {
+ if (auto EC = dumpTpiStream(StreamIPI))
+ return EC;
+ }
}
if (opts::dump::DumpGlobals) {
@@ -913,15 +921,17 @@ static void buildDepSet(LazyRandomTypeCollection &Types,
}
}
-static void dumpFullTypeStream(LinePrinter &Printer,
- LazyRandomTypeCollection &Types,
- TpiStream &Stream, bool Bytes, bool Extras) {
- Printer.formatLine("Showing {0:N} records", Stream.getNumTypeRecords());
- uint32_t Width =
- NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords());
+static void
+dumpFullTypeStream(LinePrinter &Printer, LazyRandomTypeCollection &Types,
+ uint32_t NumHashBuckets,
+ FixedStreamArray<support::ulittle32_t> HashValues,
+ bool Bytes, bool Extras) {
+
+ Printer.formatLine("Showing {0:N} records", Types.size());
+ uint32_t Width = NumDigits(TypeIndex::FirstNonSimpleIndex + Types.size());
MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types,
- Stream.getNumHashBuckets(), Stream.getHashValues());
+ NumHashBuckets, HashValues);
if (auto EC = codeview::visitTypeStream(Types, V)) {
Printer.formatLine("An error occurred dumping type records: {0}",
@@ -967,6 +977,55 @@ static void dumpPartialTypeStream(LinePrinter &Printer,
}
}
+Error DumpOutputStyle::dumpTypesFromObjectFile() {
+ LazyRandomTypeCollection Types(100);
+
+ for (const auto &S : getObj().sections()) {
+ StringRef SectionName;
+ if (auto EC = S.getName(SectionName))
+ return errorCodeToError(EC);
+
+ if (SectionName != ".debug$T")
+ continue;
+ StringRef Contents;
+ if (auto EC = S.getContents(Contents))
+ return errorCodeToError(EC);
+
+ uint32_t Magic;
+ BinaryStreamReader Reader(Contents, llvm::support::little);
+ if (auto EC = Reader.readInteger(Magic))
+ return EC;
+ if (Magic != COFF::DEBUG_SECTION_MAGIC)
+ return make_error<StringError>("Invalid CodeView debug section.",
+ inconvertibleErrorCode());
+
+ Types.reset(Reader, 100);
+
+ if (opts::dump::DumpTypes) {
+ dumpFullTypeStream(P, Types, 0, {}, opts::dump::DumpTypeData, false);
+ } else if (opts::dump::DumpTypeExtras) {
+ auto LocalHashes = LocallyHashedType::hashTypeCollection(Types);
+ auto GlobalHashes = GloballyHashedType::hashTypeCollection(Types);
+ assert(LocalHashes.size() == GlobalHashes.size());
+
+ P.formatLine("Local / Global hashes:");
+ TypeIndex TI(TypeIndex::FirstNonSimpleIndex);
+ for (const auto &H : zip(LocalHashes, GlobalHashes)) {
+ AutoIndent Indent2(P);
+ LocallyHashedType &L = std::get<0>(H);
+ GloballyHashedType &G = std::get<1>(H);
+
+ P.formatLine("TI: {0}, LocalHash: {1:X}, GlobalHash: {2}", TI, L, G);
+
+ ++TI;
+ }
+ P.NewLine();
+ }
+ }
+
+ return Error::success();
+}
+
Error DumpOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);
@@ -977,10 +1036,7 @@ Error DumpOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
}
AutoIndent Indent(P);
- if (File.isObj()) {
- P.formatLine("Dumping types is not supported for object files");
- return Error::success();
- }
+ assert(!File.isObj());
bool Present = false;
bool DumpTypes = false;
@@ -1017,7 +1073,8 @@ Error DumpOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
if (DumpTypes || !Indices.empty()) {
if (Indices.empty())
- dumpFullTypeStream(P, Types, Stream, DumpBytes, DumpExtras);
+ dumpFullTypeStream(P, Types, Stream.getNumHashBuckets(),
+ Stream.getHashValues(), DumpBytes, DumpExtras);
else {
std::vector<TypeIndex> TiList(Indices.begin(), Indices.end());
dumpPartialTypeStream(P, Types, Stream, TiList, DumpBytes, DumpExtras,
diff --git a/tools/llvm-pdbutil/DumpOutputStyle.h b/tools/llvm-pdbutil/DumpOutputStyle.h
index 85598307863..3ce2884b271 100644
--- a/tools/llvm-pdbutil/DumpOutputStyle.h
+++ b/tools/llvm-pdbutil/DumpOutputStyle.h
@@ -80,6 +80,7 @@ private:
Error dumpXmi();
Error dumpXme();
Error dumpTpiStream(uint32_t StreamIdx);
+ Error dumpTypesFromObjectFile();
Error dumpModules();
Error dumpModuleFiles();
Error dumpModuleSymsForPdb();
diff --git a/tools/llvm-readobj/COFFDumper.cpp b/tools/llvm-readobj/COFFDumper.cpp
index ca2a9ec1615..0c7f7db5760 100644
--- a/tools/llvm-readobj/COFFDumper.cpp
+++ b/tools/llvm-readobj/COFFDumper.cpp
@@ -38,6 +38,7 @@
#include "llvm/DebugInfo/CodeView/SymbolDumper.h"
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
+#include "llvm/DebugInfo/CodeView/TypeHashing.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"