summaryrefslogtreecommitdiffstats
path: root/llvm/unittests/DebugInfo/PDB
diff options
context:
space:
mode:
authorZachary Turner <zturner@google.com>2017-02-16 23:35:45 +0000
committerZachary Turner <zturner@google.com>2017-02-16 23:35:45 +0000
commit7b327d051b12f90e4650a8ac48cd3f7b3ee1c4e9 (patch)
tree8bf152120db1248d4f0a38028cda19909986f907 /llvm/unittests/DebugInfo/PDB
parent55aaa844cb12923529c9ff128be22cdaddcce9dd (diff)
downloadbcm5719-llvm-7b327d051b12f90e4650a8ac48cd3f7b3ee1c4e9.tar.gz
bcm5719-llvm-7b327d051b12f90e4650a8ac48cd3f7b3ee1c4e9.zip
[pdb] Add the ability to resolve TypeServer PDBs.
Some PDBs or object files can contain references to other PDBs where the real type information lives. When this happens, all type indices in the original PDB are meaningless because their records are not there. With this patch we add the ability to pull type info from those secondary PDBs. Differential Revision: https://reviews.llvm.org/D29973 llvm-svn: 295382
Diffstat (limited to 'llvm/unittests/DebugInfo/PDB')
-rw-r--r--llvm/unittests/DebugInfo/PDB/CMakeLists.txt1
-rw-r--r--llvm/unittests/DebugInfo/PDB/TypeServerHandlerTest.cpp175
2 files changed, 176 insertions, 0 deletions
diff --git a/llvm/unittests/DebugInfo/PDB/CMakeLists.txt b/llvm/unittests/DebugInfo/PDB/CMakeLists.txt
index 3ba3196ed1c..cbbbd817748 100644
--- a/llvm/unittests/DebugInfo/PDB/CMakeLists.txt
+++ b/llvm/unittests/DebugInfo/PDB/CMakeLists.txt
@@ -10,6 +10,7 @@ set(DebugInfoPDBSources
StringTableBuilderTest.cpp
MSFBuilderTest.cpp
PDBApiTest.cpp
+ TypeServerHandlerTest.cpp
)
add_llvm_unittest(DebugInfoPDBTests
diff --git a/llvm/unittests/DebugInfo/PDB/TypeServerHandlerTest.cpp b/llvm/unittests/DebugInfo/PDB/TypeServerHandlerTest.cpp
new file mode 100644
index 00000000000..6995e8f9dde
--- /dev/null
+++ b/llvm/unittests/DebugInfo/PDB/TypeServerHandlerTest.cpp
@@ -0,0 +1,175 @@
+//===- llvm/unittest/DebugInfo/PDB/TypeServerHandlerTest.cpp --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ErrorChecking.h"
+
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
+#include "llvm/DebugInfo/CodeView/TypeSerializer.h"
+#include "llvm/DebugInfo/CodeView/TypeServerHandler.h"
+#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
+#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Error.h"
+
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+namespace {
+
+constexpr uint8_t Guid[] = {0x2a, 0x2c, 0x1c, 0x2a, 0xcb, 0x9e, 0x48, 0x18,
+ 0x82, 0x82, 0x7a, 0x87, 0xc3, 0xfe, 0x16, 0xe8};
+StringRef GuidStr(reinterpret_cast<const char *>(Guid),
+ llvm::array_lengthof(Guid));
+
+constexpr const char *Name = "Test Name";
+constexpr int Age = 1;
+
+class MockTypeServerHandler : public TypeServerHandler {
+public:
+ explicit MockTypeServerHandler(bool HandleAlways)
+ : HandleAlways(HandleAlways) {}
+
+ Expected<bool> handle(TypeServer2Record &TS,
+ TypeVisitorCallbacks &Callbacks) override {
+ if (TS.Age != Age || TS.Guid != GuidStr || TS.Name != Name)
+ return make_error<CodeViewError>(cv_error_code::corrupt_record,
+ "Invalid TypeServer record!");
+
+ if (Handled && !HandleAlways)
+ return false;
+
+ Handled = true;
+ return true;
+ }
+
+ bool Handled = false;
+ bool HandleAlways;
+};
+
+class MockTypeVisitorCallbacks : public TypeVisitorCallbacks {
+public:
+ enum class State {
+ Ready,
+ VisitTypeBegin,
+ VisitKnownRecord,
+ VisitTypeEnd,
+ };
+ Error visitTypeBegin(CVType &CVT) override {
+ if (S != State::Ready)
+ return make_error<CodeViewError>(cv_error_code::unspecified,
+ "Invalid visitor state!");
+
+ S = State::VisitTypeBegin;
+ return Error::success();
+ }
+
+ Error visitKnownRecord(CVType &CVT, TypeServer2Record &TS) override {
+ if (S != State::VisitTypeBegin)
+ return make_error<CodeViewError>(cv_error_code::unspecified,
+ "Invalid visitor state!");
+
+ S = State::VisitKnownRecord;
+ return Error::success();
+ }
+
+ Error visitTypeEnd(CVType &CVT) override {
+ if (S != State::VisitKnownRecord)
+ return make_error<CodeViewError>(cv_error_code::unspecified,
+ "Invalid visitor state!");
+
+ S = State::VisitTypeEnd;
+ return Error::success();
+ }
+
+ State S = State::Ready;
+};
+
+class TypeServerHandlerTest : public testing::Test {
+public:
+ void SetUp() override {
+ TypeServer2Record R(TypeRecordKind::TypeServer2);
+ R.Age = Age;
+ R.Guid = GuidStr;
+ R.Name = Name;
+
+ TypeTableBuilder Builder(Allocator);
+ Builder.writeKnownType(R);
+ TypeServerRecord.RecordData = Builder.records().front();
+ TypeServerRecord.Type = TypeLeafKind::LF_TYPESERVER2;
+ }
+
+protected:
+ BumpPtrAllocator Allocator;
+ CVType TypeServerRecord;
+};
+
+// Test that when no type server handler is registered, it gets handled by the
+// normal
+// visitor callbacks.
+TEST_F(TypeServerHandlerTest, VisitRecordNoTypeServer) {
+ MockTypeVisitorCallbacks C2;
+ MockTypeVisitorCallbacks C1;
+ TypeVisitorCallbackPipeline Pipeline;
+
+ Pipeline.addCallbackToPipeline(C1);
+ Pipeline.addCallbackToPipeline(C2);
+ CVTypeVisitor Visitor(Pipeline);
+ EXPECT_NO_ERROR(Visitor.visitTypeRecord(TypeServerRecord));
+
+ EXPECT_EQ(MockTypeVisitorCallbacks::State::VisitTypeEnd, C1.S);
+ EXPECT_EQ(MockTypeVisitorCallbacks::State::VisitTypeEnd, C2.S);
+}
+
+// Test that when a TypeServerHandler is registered, it gets consumed by the
+// handler if and only if the handler returns true.
+TEST_F(TypeServerHandlerTest, VisitRecordWithTypeServerOnce) {
+ MockTypeServerHandler Handler(false);
+
+ MockTypeVisitorCallbacks C1;
+ CVTypeVisitor Visitor(C1);
+ Visitor.addTypeServerHandler(Handler);
+
+ // Our mock server returns true the first time.
+ EXPECT_NO_ERROR(Visitor.visitTypeRecord(TypeServerRecord));
+ EXPECT_TRUE(Handler.Handled);
+ EXPECT_EQ(MockTypeVisitorCallbacks::State::Ready, C1.S);
+
+ // And false the second time.
+ EXPECT_NO_ERROR(Visitor.visitTypeRecord(TypeServerRecord));
+ EXPECT_TRUE(Handler.Handled);
+ EXPECT_EQ(MockTypeVisitorCallbacks::State::VisitTypeEnd, C1.S);
+}
+
+// Test that when a type server handler is registered, if the handler keeps
+// returning true, it will keep getting consumed by the handler and not go
+// to the default processor.
+TEST_F(TypeServerHandlerTest, VisitRecordWithTypeServerAlways) {
+ MockTypeServerHandler Handler(true);
+
+ MockTypeVisitorCallbacks C1;
+ CVTypeVisitor Visitor(C1);
+ Visitor.addTypeServerHandler(Handler);
+
+ EXPECT_NO_ERROR(Visitor.visitTypeRecord(TypeServerRecord));
+ EXPECT_TRUE(Handler.Handled);
+ EXPECT_EQ(MockTypeVisitorCallbacks::State::Ready, C1.S);
+
+ EXPECT_NO_ERROR(Visitor.visitTypeRecord(TypeServerRecord));
+ EXPECT_TRUE(Handler.Handled);
+ EXPECT_EQ(MockTypeVisitorCallbacks::State::Ready, C1.S);
+}
+
+} // end anonymous namespace
OpenPOWER on IntegriCloud