summaryrefslogtreecommitdiffstats
path: root/llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp')
-rw-r--r--llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp254
1 files changed, 254 insertions, 0 deletions
diff --git a/llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp b/llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp
index 421544ee1d4..90d8594eec6 100644
--- a/llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp
+++ b/llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp
@@ -13,6 +13,8 @@
#include "llvm/DebugInfo/GSYM/FileEntry.h"
#include "llvm/DebugInfo/GSYM/FileWriter.h"
#include "llvm/DebugInfo/GSYM/FunctionInfo.h"
+#include "llvm/DebugInfo/GSYM/GsymCreator.h"
+#include "llvm/DebugInfo/GSYM/GsymReader.h"
#include "llvm/DebugInfo/GSYM/InlineInfo.h"
#include "llvm/DebugInfo/GSYM/Range.h"
#include "llvm/DebugInfo/GSYM/StringTable.h"
@@ -1046,3 +1048,255 @@ TEST(GSYMTest, TestHeaderEncodeDecode) {
TestHeaderEncodeDecode(H, llvm::support::little);
TestHeaderEncodeDecode(H, llvm::support::big);
}
+
+static void TestGsymCreatorEncodeError(llvm::support::endianness ByteOrder,
+ const GsymCreator &GC,
+ std::string ExpectedErrorMsg) {
+ SmallString<512> Str;
+ raw_svector_ostream OutStrm(Str);
+ FileWriter FW(OutStrm, ByteOrder);
+ llvm::Error Err = GC.encode(FW);
+ ASSERT_TRUE(bool(Err));
+ checkError(ExpectedErrorMsg, std::move(Err));
+}
+
+TEST(GSYMTest, TestGsymCreatorEncodeErrors) {
+ const uint8_t ValidUUID[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 14, 15, 16};
+ const uint8_t InvalidUUID[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21};
+ // Verify we get an error when trying to encode an GsymCreator with no
+ // function infos. We shouldn't be saving a GSYM file in this case since
+ // there is nothing inside of it.
+ GsymCreator GC;
+ TestGsymCreatorEncodeError(llvm::support::little, GC,
+ "no functions to encode");
+ const uint64_t FuncAddr = 0x1000;
+ const uint64_t FuncSize = 0x100;
+ const uint32_t FuncName = GC.insertString("foo");
+ // Verify we get an error trying to encode a GsymCreator that isn't
+ // finalized.
+ GC.addFunctionInfo(FunctionInfo(FuncAddr, FuncSize, FuncName));
+ TestGsymCreatorEncodeError(llvm::support::little, GC,
+ "GsymCreator wasn't finalized prior to encoding");
+ std::string finalizeIssues;
+ raw_string_ostream OS(finalizeIssues);
+ llvm::Error finalizeErr = GC.finalize(OS);
+ ASSERT_FALSE(bool(finalizeErr));
+ finalizeErr = GC.finalize(OS);
+ ASSERT_TRUE(bool(finalizeErr));
+ checkError("already finalized", std::move(finalizeErr));
+ // Verify we get an error trying to encode a GsymCreator with a UUID that is
+ // too long.
+ GC.setUUID(InvalidUUID);
+ TestGsymCreatorEncodeError(llvm::support::little, GC,
+ "invalid UUID size 21");
+ GC.setUUID(ValidUUID);
+ // Verify errors are propagated when we try to encoding an invalid line
+ // table.
+ GC.forEachFunctionInfo([](FunctionInfo &FI) -> bool {
+ FI.OptLineTable = LineTable(); // Invalid line table.
+ return false; // Stop iterating
+ });
+ TestGsymCreatorEncodeError(llvm::support::little, GC,
+ "attempted to encode invalid LineTable object");
+ // Verify errors are propagated when we try to encoding an invalid inline
+ // info.
+ GC.forEachFunctionInfo([](FunctionInfo &FI) -> bool {
+ FI.OptLineTable = llvm::None;
+ FI.Inline = InlineInfo(); // Invalid InlineInfo.
+ return false; // Stop iterating
+ });
+ TestGsymCreatorEncodeError(llvm::support::little, GC,
+ "attempted to encode invalid InlineInfo object");
+}
+
+static void Compare(const GsymCreator &GC, const GsymReader &GR) {
+ // Verify that all of the data in a GsymCreator is correctly decoded from
+ // a GsymReader. To do this, we iterator over
+ GC.forEachFunctionInfo([&](const FunctionInfo &FI) -> bool {
+ auto DecodedFI = GR.getFunctionInfo(FI.Range.Start);
+ EXPECT_TRUE(bool(DecodedFI));
+ EXPECT_EQ(FI, *DecodedFI);
+ return true; // Keep iterating over all FunctionInfo objects.
+ });
+}
+
+static void TestEncodeDecode(const GsymCreator &GC,
+ support::endianness ByteOrder, uint16_t Version,
+ uint8_t AddrOffSize, uint64_t BaseAddress,
+ uint32_t NumAddresses, ArrayRef<uint8_t> UUID) {
+ SmallString<512> Str;
+ raw_svector_ostream OutStrm(Str);
+ FileWriter FW(OutStrm, ByteOrder);
+ llvm::Error Err = GC.encode(FW);
+ ASSERT_FALSE((bool)Err);
+ Expected<GsymReader> GR = GsymReader::copyBuffer(OutStrm.str());
+ ASSERT_TRUE(bool(GR));
+ const Header &Hdr = GR->getHeader();
+ EXPECT_EQ(Hdr.Version, Version);
+ EXPECT_EQ(Hdr.AddrOffSize, AddrOffSize);
+ EXPECT_EQ(Hdr.UUIDSize, UUID.size());
+ EXPECT_EQ(Hdr.BaseAddress, BaseAddress);
+ EXPECT_EQ(Hdr.NumAddresses, NumAddresses);
+ EXPECT_EQ(ArrayRef<uint8_t>(Hdr.UUID, Hdr.UUIDSize), UUID);
+ Compare(GC, GR.get());
+}
+
+TEST(GSYMTest, TestGsymCreator1ByteAddrOffsets) {
+ uint8_t UUID[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+ GsymCreator GC;
+ GC.setUUID(UUID);
+ constexpr uint64_t BaseAddr = 0x1000;
+ constexpr uint8_t AddrOffSize = 1;
+ const uint32_t Func1Name = GC.insertString("foo");
+ const uint32_t Func2Name = GC.insertString("bar");
+ GC.addFunctionInfo(FunctionInfo(BaseAddr+0x00, 0x10, Func1Name));
+ GC.addFunctionInfo(FunctionInfo(BaseAddr+0x20, 0x10, Func2Name));
+ Error Err = GC.finalize(llvm::nulls());
+ ASSERT_FALSE(Err);
+ TestEncodeDecode(GC, llvm::support::little,
+ GSYM_VERSION,
+ AddrOffSize,
+ BaseAddr,
+ 2, // NumAddresses
+ ArrayRef<uint8_t>(UUID));
+ TestEncodeDecode(GC, llvm::support::big,
+ GSYM_VERSION,
+ AddrOffSize,
+ BaseAddr,
+ 2, // NumAddresses
+ ArrayRef<uint8_t>(UUID));
+}
+
+TEST(GSYMTest, TestGsymCreator2ByteAddrOffsets) {
+ uint8_t UUID[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+ GsymCreator GC;
+ GC.setUUID(UUID);
+ constexpr uint64_t BaseAddr = 0x1000;
+ constexpr uint8_t AddrOffSize = 2;
+ const uint32_t Func1Name = GC.insertString("foo");
+ const uint32_t Func2Name = GC.insertString("bar");
+ GC.addFunctionInfo(FunctionInfo(BaseAddr+0x000, 0x100, Func1Name));
+ GC.addFunctionInfo(FunctionInfo(BaseAddr+0x200, 0x100, Func2Name));
+ Error Err = GC.finalize(llvm::nulls());
+ ASSERT_FALSE(Err);
+ TestEncodeDecode(GC, llvm::support::little,
+ GSYM_VERSION,
+ AddrOffSize,
+ BaseAddr,
+ 2, // NumAddresses
+ ArrayRef<uint8_t>(UUID));
+ TestEncodeDecode(GC, llvm::support::big,
+ GSYM_VERSION,
+ AddrOffSize,
+ BaseAddr,
+ 2, // NumAddresses
+ ArrayRef<uint8_t>(UUID));
+}
+
+TEST(GSYMTest, TestGsymCreator4ByteAddrOffsets) {
+ uint8_t UUID[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+ GsymCreator GC;
+ GC.setUUID(UUID);
+ constexpr uint64_t BaseAddr = 0x1000;
+ constexpr uint8_t AddrOffSize = 4;
+ const uint32_t Func1Name = GC.insertString("foo");
+ const uint32_t Func2Name = GC.insertString("bar");
+ GC.addFunctionInfo(FunctionInfo(BaseAddr+0x000, 0x100, Func1Name));
+ GC.addFunctionInfo(FunctionInfo(BaseAddr+0x20000, 0x100, Func2Name));
+ Error Err = GC.finalize(llvm::nulls());
+ ASSERT_FALSE(Err);
+ TestEncodeDecode(GC, llvm::support::little,
+ GSYM_VERSION,
+ AddrOffSize,
+ BaseAddr,
+ 2, // NumAddresses
+ ArrayRef<uint8_t>(UUID));
+ TestEncodeDecode(GC, llvm::support::big,
+ GSYM_VERSION,
+ AddrOffSize,
+ BaseAddr,
+ 2, // NumAddresses
+ ArrayRef<uint8_t>(UUID));
+}
+
+TEST(GSYMTest, TestGsymCreator8ByteAddrOffsets) {
+ uint8_t UUID[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+ GsymCreator GC;
+ GC.setUUID(UUID);
+ constexpr uint64_t BaseAddr = 0x1000;
+ constexpr uint8_t AddrOffSize = 8;
+ const uint32_t Func1Name = GC.insertString("foo");
+ const uint32_t Func2Name = GC.insertString("bar");
+ GC.addFunctionInfo(FunctionInfo(BaseAddr+0x000, 0x100, Func1Name));
+ GC.addFunctionInfo(FunctionInfo(BaseAddr+0x100000000, 0x100, Func2Name));
+ Error Err = GC.finalize(llvm::nulls());
+ ASSERT_FALSE(Err);
+ TestEncodeDecode(GC, llvm::support::little,
+ GSYM_VERSION,
+ AddrOffSize,
+ BaseAddr,
+ 2, // NumAddresses
+ ArrayRef<uint8_t>(UUID));
+ TestEncodeDecode(GC, llvm::support::big,
+ GSYM_VERSION,
+ AddrOffSize,
+ BaseAddr,
+ 2, // NumAddresses
+ ArrayRef<uint8_t>(UUID));
+}
+
+static void VerifyFunctionInfo(const GsymReader &GR, uint64_t Addr,
+ const FunctionInfo &FI) {
+ auto ExpFI = GR.getFunctionInfo(Addr);
+ ASSERT_TRUE(bool(ExpFI));
+ ASSERT_EQ(FI, ExpFI.get());
+}
+
+static void VerifyFunctionInfoError(const GsymReader &GR, uint64_t Addr,
+ std::string ErrMessage) {
+ auto ExpFI = GR.getFunctionInfo(Addr);
+ ASSERT_FALSE(bool(ExpFI));
+ checkError(ErrMessage, ExpFI.takeError());
+}
+
+TEST(GSYMTest, TestGsymReader) {
+ uint8_t UUID[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+ GsymCreator GC;
+ GC.setUUID(UUID);
+ constexpr uint64_t BaseAddr = 0x1000;
+ constexpr uint64_t Func1Addr = BaseAddr;
+ constexpr uint64_t Func2Addr = BaseAddr+0x20;
+ constexpr uint64_t FuncSize = 0x10;
+ const uint32_t Func1Name = GC.insertString("foo");
+ const uint32_t Func2Name = GC.insertString("bar");
+ const auto ByteOrder = support::endian::system_endianness();
+ GC.addFunctionInfo(FunctionInfo(Func1Addr, FuncSize, Func1Name));
+ GC.addFunctionInfo(FunctionInfo(Func2Addr, FuncSize, Func2Name));
+ Error FinalizeErr = GC.finalize(llvm::nulls());
+ ASSERT_FALSE(FinalizeErr);
+ SmallString<512> Str;
+ raw_svector_ostream OutStrm(Str);
+ FileWriter FW(OutStrm, ByteOrder);
+ llvm::Error Err = GC.encode(FW);
+ ASSERT_FALSE((bool)Err);
+ if (auto ExpectedGR = GsymReader::copyBuffer(OutStrm.str())) {
+ const GsymReader &GR = ExpectedGR.get();
+ VerifyFunctionInfoError(GR, Func1Addr-1, "address 0xfff not in GSYM");
+
+ FunctionInfo Func1(Func1Addr, FuncSize, Func1Name);
+ VerifyFunctionInfo(GR, Func1Addr, Func1);
+ VerifyFunctionInfo(GR, Func1Addr+1, Func1);
+ VerifyFunctionInfo(GR, Func1Addr+FuncSize-1, Func1);
+ VerifyFunctionInfoError(GR, Func1Addr+FuncSize,
+ "address 0x1010 not in GSYM");
+ VerifyFunctionInfoError(GR, Func2Addr-1, "address 0x101f not in GSYM");
+ FunctionInfo Func2(Func2Addr, FuncSize, Func2Name);
+ VerifyFunctionInfo(GR, Func2Addr, Func2);
+ VerifyFunctionInfo(GR, Func2Addr+1, Func2);
+ VerifyFunctionInfo(GR, Func2Addr+FuncSize-1, Func2);
+ VerifyFunctionInfoError(GR, Func2Addr+FuncSize,
+ "address 0x1030 not in GSYM");
+ }
+}
OpenPOWER on IntegriCloud