xref: /llvm-project/llvm/unittests/Object/ELFTypesTest.cpp (revision cf83a7fdc2dfac8220d9923a831181dccb9f7277)
1 //===----------------------- ELFTypesTest.cpp -----------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 #include "llvm/Object/ELFTypes.h"
9 #include "llvm/Testing/Support/Error.h"
10 #include "gtest/gtest.h"
11 #include <iostream>
12 
13 using namespace llvm;
14 using namespace llvm::object;
15 
16 template <typename ELFT> using Elf_Note = typename ELFT::Note;
17 
18 template <class ELFT> struct NoteTestData {
19   std::vector<uint8_t> Data;
20 
21   const Elf_Note_Impl<ELFT> getElfNote(StringRef Name, uint32_t Type,
22                                        ArrayRef<uint8_t> Desc) {
23     constexpr uint64_t Align = 4;
24     Data.resize(alignTo(sizeof(Elf_Nhdr_Impl<ELFT>) + Name.size(), Align) +
25                     alignTo(Desc.size(), Align),
26                 0);
27 
28     Elf_Nhdr_Impl<ELFT> *Nhdr =
29         reinterpret_cast<Elf_Nhdr_Impl<ELFT> *>(Data.data());
30     Nhdr->n_namesz = (Name == "") ? 0 : Name.size() + 1;
31     Nhdr->n_descsz = Desc.size();
32     Nhdr->n_type = Type;
33 
34     auto NameOffset = Data.begin() + sizeof(*Nhdr);
35     std::copy(Name.begin(), Name.end(), NameOffset);
36 
37     auto DescOffset =
38         Data.begin() + alignTo(sizeof(*Nhdr) + Nhdr->n_namesz, Align);
39     std::copy(Desc.begin(), Desc.end(), DescOffset);
40 
41     return Elf_Note_Impl<ELFT>(*Nhdr);
42   }
43 };
44 
45 TEST(ELFTypesTest, NoteTest) {
46   static const uint8_t Random[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
47   ArrayRef<uint8_t> RandomData = ArrayRef(Random);
48   NoteTestData<ELF64LE> TestData;
49 
50   auto Note1 = TestData.getElfNote(StringRef("AMD"), ELF::NT_AMDGPU_METADATA,
51                                    RandomData);
52   EXPECT_EQ(Note1.getName(), "AMD");
53   EXPECT_EQ(Note1.getType(), ELF::NT_AMDGPU_METADATA);
54   EXPECT_EQ(Note1.getDesc(4), RandomData);
55   EXPECT_EQ(Note1.getDescAsStringRef(4),
56             StringRef(reinterpret_cast<const char *>(Random), sizeof(Random)));
57 
58   auto Note2 = TestData.getElfNote("", ELF::NT_AMDGPU_METADATA, RandomData);
59   EXPECT_EQ(Note2.getName(), "");
60 
61   auto Note3 =
62       TestData.getElfNote("AMD", ELF::NT_AMDGPU_METADATA, ArrayRef<uint8_t>());
63   EXPECT_EQ(Note3.getDescAsStringRef(4), StringRef(""));
64 }
65 
66 TEST(ELFTypesTest, BBEntryMetadataEncodingTest) {
67   const std::array<BBAddrMap::BBEntry::Metadata, 7> Decoded = {
68       {{false, false, false, false, false},
69        {true, false, false, false, false},
70        {false, true, false, false, false},
71        {false, false, true, false, false},
72        {false, false, false, true, false},
73        {false, false, false, false, true},
74        {true, true, true, true, true}}};
75   const std::array<uint32_t, 7> Encoded = {{0, 1, 2, 4, 8, 16, 31}};
76   for (size_t i = 0; i < Decoded.size(); ++i)
77     EXPECT_EQ(Decoded[i].encode(), Encoded[i]);
78   for (size_t i = 0; i < Encoded.size(); ++i) {
79     Expected<BBAddrMap::BBEntry::Metadata> MetadataOrError =
80         BBAddrMap::BBEntry::Metadata::decode(Encoded[i]);
81     ASSERT_THAT_EXPECTED(MetadataOrError, Succeeded());
82     EXPECT_EQ(*MetadataOrError, Decoded[i]);
83   }
84 }
85 
86 TEST(ELFTypesTest, BBEntryMetadataInvalidEncodingTest) {
87   const std::array<std::string, 2> Errors = {
88       "invalid encoding for BBEntry::Metadata: 0xffff",
89       "invalid encoding for BBEntry::Metadata: 0x100001"};
90   const std::array<uint32_t, 2> Values = {{0xFFFF, 0x100001}};
91   for (size_t i = 0; i < Values.size(); ++i) {
92     EXPECT_THAT_ERROR(
93         BBAddrMap::BBEntry::Metadata::decode(Values[i]).takeError(),
94         FailedWithMessage(Errors[i]));
95   }
96 }
97 
98 static_assert(
99     std::is_same_v<decltype(PGOAnalysisMap::PGOBBEntry::SuccessorEntry::ID),
100                    decltype(BBAddrMap::BBEntry::ID)>,
101     "PGOAnalysisMap should use the same type for basic block ID as BBAddrMap");
102 
103 TEST(ELFTypesTest, BBAddrMapFeaturesEncodingTest) {
104   const std::array<BBAddrMap::Features, 9> Decoded = {
105       {{false, false, false, false, false},
106        {true, false, false, false, false},
107        {false, true, false, false, false},
108        {false, false, true, false, false},
109        {false, false, false, true, false},
110        {true, true, false, false, false},
111        {false, true, true, false, false},
112        {false, true, true, true, false},
113        {true, true, true, true, false}}};
114   const std::array<uint8_t, 9> Encoded = {
115       {0b0000, 0b0001, 0b0010, 0b0100, 0b1000, 0b0011, 0b0110, 0b1110, 0b1111}};
116   for (const auto &[Feat, EncodedVal] : llvm::zip(Decoded, Encoded))
117     EXPECT_EQ(Feat.encode(), EncodedVal);
118   for (const auto &[Feat, EncodedVal] : llvm::zip(Decoded, Encoded)) {
119     Expected<BBAddrMap::Features> FeatEnableOrError =
120         BBAddrMap::Features::decode(EncodedVal);
121     ASSERT_THAT_EXPECTED(FeatEnableOrError, Succeeded());
122     EXPECT_EQ(*FeatEnableOrError, Feat);
123   }
124 }
125 
126 TEST(ELFTypesTest, BBAddrMapFeaturesInvalidEncodingTest) {
127   const std::array<std::string, 2> Errors = {
128       "invalid encoding for BBAddrMap::Features: 0x20",
129       "invalid encoding for BBAddrMap::Features: 0xf0"};
130   const std::array<uint8_t, 2> Values = {{0b10'0000, 0b1111'0000}};
131   for (const auto &[Val, Error] : llvm::zip(Values, Errors)) {
132     EXPECT_THAT_ERROR(BBAddrMap::Features::decode(Val).takeError(),
133                       FailedWithMessage(Error));
134   }
135 }
136