//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/PDB/Native/TpiStream.h" #include "llvm/DebugInfo/PDB/Native/NativeSession.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/PDB.h" #include "llvm/Support/Path.h" #include "llvm/Testing/Support/Error.h" #include "gtest/gtest.h" using namespace llvm; using namespace llvm::pdb; using namespace llvm::codeview; extern const char *TestMainArgv0; // FIXME: This should use ObjectYAML to create a PDB from YAML. static std::string getPdbPath() { SmallString<128> InputsDir = unittest::getInputFileDirectory(TestMainArgv0); llvm::sys::path::append(InputsDir, "SimpleTest.pdb"); return std::string(InputsDir); } // Types: // 0x1000 | LF_ARGLIST [size = 8] // 0x1001 | LF_PROCEDURE [size = 16] static Expected> openSimplePdb(BumpPtrAllocator &Allocator) { std::string PdbPath = getPdbPath(); ErrorOr> ErrorOrBuffer = MemoryBuffer::getFile(PdbPath, /*IsText=*/false, /*RequiresNullTerminator=*/false); EXPECT_TRUE(ErrorOrBuffer); std::unique_ptr Buffer = std::move(*ErrorOrBuffer); auto Stream = std::make_unique( std::move(Buffer), llvm::endianness::little); auto File = std::make_unique(PdbPath, std::move(Stream), Allocator); if (Error Err = File->parseFileHeaders()) return Err; if (Error Err = File->parseStreamData()) return Err; return File; } TEST(TpiStreamTest, getType) { BumpPtrAllocator Allocator; Expected> FileOrErr = openSimplePdb(Allocator); ASSERT_TRUE(!!FileOrErr); std::unique_ptr File = std::move(*FileOrErr); Expected Tpi = File->getPDBTpiStream(); ASSERT_TRUE(!!Tpi) << Tpi.takeError(); ASSERT_EQ(Tpi->getType(TypeIndex(0x1000)).kind(), LF_ARGLIST); ASSERT_EQ(Tpi->getType(TypeIndex(0x1001)).kind(), LF_PROCEDURE); } TEST(TpiStreamTest, getTypeOrEmpty) { BumpPtrAllocator Allocator; Expected> FileOrErr = openSimplePdb(Allocator); ASSERT_TRUE(!!FileOrErr); std::unique_ptr File = std::move(*FileOrErr); Expected Tpi = File->getPDBTpiStream(); ASSERT_TRUE(!!Tpi); ASSERT_FALSE(Tpi->getTypeOrEmpty(TypeIndex(0)).valid()); ASSERT_FALSE(Tpi->getTypeOrEmpty(TypeIndex(0xFFF)).valid()); ASSERT_FALSE(Tpi->getTypeOrEmpty(TypeIndex(0x1002)).valid()); ASSERT_FALSE(Tpi->getTypeOrEmpty(TypeIndex(0x1003)).valid()); ASSERT_FALSE(Tpi->getTypeOrEmpty(TypeIndex(0x1234567)).valid()); ASSERT_EQ(Tpi->getTypeOrEmpty(TypeIndex(0x1000)).kind(), LF_ARGLIST); ASSERT_EQ(Tpi->getTypeOrEmpty(TypeIndex(0x1001)).kind(), LF_PROCEDURE); } TEST(TpiStreamTest, tryGetType) { BumpPtrAllocator Allocator; Expected> FileOrErr = openSimplePdb(Allocator); ASSERT_TRUE(!!FileOrErr); std::unique_ptr File = std::move(*FileOrErr); Expected Tpi = File->getPDBTpiStream(); ASSERT_TRUE(!!Tpi); ASSERT_FALSE(Tpi->tryGetType(TypeIndex(0)).has_value()); ASSERT_FALSE(Tpi->tryGetType(TypeIndex(0xFFF)).has_value()); ASSERT_FALSE(Tpi->tryGetType(TypeIndex(0x1002)).has_value()); ASSERT_FALSE(Tpi->tryGetType(TypeIndex(0x1003)).has_value()); ASSERT_FALSE(Tpi->tryGetType(TypeIndex(0x1234567)).has_value()); std::optional T0 = Tpi->tryGetType(TypeIndex(0x1000)); std::optional T1 = Tpi->tryGetType(TypeIndex(0x1001)); ASSERT_TRUE(T0.has_value()); ASSERT_EQ(T0->kind(), LF_ARGLIST); ASSERT_TRUE(T1.has_value()); ASSERT_EQ(T1->kind(), LF_PROCEDURE); } TEST(TpiStreamTest, getTypeOrErr) { BumpPtrAllocator Allocator; Expected> FileOrErr = openSimplePdb(Allocator); ASSERT_TRUE(!!FileOrErr); std::unique_ptr File = std::move(*FileOrErr); Expected Tpi = File->getPDBTpiStream(); ASSERT_TRUE(!!Tpi); Expected E0 = Tpi->getTypeOrError(TypeIndex(0)); ASSERT_FALSE(E0); ASSERT_EQ(toString(E0.takeError()), "Type index too low (0)"); Expected E1 = Tpi->getTypeOrError(TypeIndex(0xFFF)); ASSERT_FALSE(E1); ASSERT_EQ(toString(E1.takeError()), "Type index too low (4095)"); Expected E2 = Tpi->getTypeOrError(TypeIndex(0x1002)); ASSERT_FALSE(E2); ASSERT_EQ(toString(E2.takeError()), "Type index too high (4098)"); Expected E3 = Tpi->getTypeOrError(TypeIndex(0x1003)); ASSERT_FALSE(E3); ASSERT_EQ(toString(E3.takeError()), "Invalid type index"); Expected E4 = Tpi->getTypeOrError(TypeIndex(0x123456)); ASSERT_FALSE(E4); ASSERT_EQ(toString(E4.takeError()), "Invalid type index"); Expected T0 = Tpi->getTypeOrError(TypeIndex(0x1000)); ASSERT_TRUE(!!T0); ASSERT_EQ(T0->kind(), LF_ARGLIST); Expected T1 = Tpi->getTypeOrError(TypeIndex(0x1001)); ASSERT_TRUE(!!T1); ASSERT_EQ(T1->kind(), LF_PROCEDURE); }