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
13using namespace llvm;
14using namespace llvm::object;
15
16template <typename ELFT> using Elf_Note = typename ELFT::Note;
17
18template <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(new_size: alignTo(Value: sizeof(Elf_Nhdr_Impl<ELFT>) + Name.size(), Align) +
25 alignTo(Value: Desc.size(), Align),
26 x: 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(first: Name.begin(), last: Name.end(), result: 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
45TEST(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(Name: StringRef("AMD"), Type: ELF::NT_AMDGPU_METADATA,
51 Desc: 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(Name: "", Type: ELF::NT_AMDGPU_METADATA, Desc: RandomData);
59 EXPECT_EQ(Note2.getName(), "");
60
61 auto Note3 =
62 TestData.getElfNote(Name: "AMD", Type: ELF::NT_AMDGPU_METADATA, Desc: ArrayRef<uint8_t>());
63 EXPECT_EQ(Note3.getDescAsStringRef(4), StringRef(""));
64}
65
66TEST(ELFTypesTest, BBEntryMetadataEncodingTest) {
67 const std::array<BBAddrMap::BBEntry::Metadata, 7> Decoded = {
68 ._M_elems: {{.HasReturn: false, .HasTailCall: false, .IsEHPad: false, .CanFallThrough: false, .HasIndirectBranch: false},
69 {.HasReturn: true, .HasTailCall: false, .IsEHPad: false, .CanFallThrough: false, .HasIndirectBranch: false},
70 {.HasReturn: false, .HasTailCall: true, .IsEHPad: false, .CanFallThrough: false, .HasIndirectBranch: false},
71 {.HasReturn: false, .HasTailCall: false, .IsEHPad: true, .CanFallThrough: false, .HasIndirectBranch: false},
72 {.HasReturn: false, .HasTailCall: false, .IsEHPad: false, .CanFallThrough: true, .HasIndirectBranch: false},
73 {.HasReturn: false, .HasTailCall: false, .IsEHPad: false, .CanFallThrough: false, .HasIndirectBranch: true},
74 {.HasReturn: true, .HasTailCall: true, .IsEHPad: true, .CanFallThrough: true, .HasIndirectBranch: true}}};
75 const std::array<uint32_t, 7> Encoded = {._M_elems: {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(V: Encoded[i]);
81 ASSERT_THAT_EXPECTED(MetadataOrError, Succeeded());
82 EXPECT_EQ(*MetadataOrError, Decoded[i]);
83 }
84}
85
86TEST(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 = {._M_elems: {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
98static_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
103TEST(ELFTypesTest, BBAddrMapFeaturesEncodingTest) {
104 const std::array<BBAddrMap::Features, 9> Decoded = {
105 ._M_elems: {{.FuncEntryCount: false, .BBFreq: false, .BrProb: false, .MultiBBRange: false},
106 {.FuncEntryCount: true, .BBFreq: false, .BrProb: false, .MultiBBRange: false},
107 {.FuncEntryCount: false, .BBFreq: true, .BrProb: false, .MultiBBRange: false},
108 {.FuncEntryCount: false, .BBFreq: false, .BrProb: true, .MultiBBRange: false},
109 {.FuncEntryCount: false, .BBFreq: false, .BrProb: false, .MultiBBRange: true},
110 {.FuncEntryCount: true, .BBFreq: true, .BrProb: false, .MultiBBRange: false},
111 {.FuncEntryCount: false, .BBFreq: true, .BrProb: true, .MultiBBRange: false},
112 {.FuncEntryCount: false, .BBFreq: true, .BrProb: true, .MultiBBRange: true},
113 {.FuncEntryCount: true, .BBFreq: true, .BrProb: true, .MultiBBRange: true}}};
114 const std::array<uint8_t, 9> Encoded = {
115 ._M_elems: {0b0000, 0b0001, 0b0010, 0b0100, 0b1000, 0b0011, 0b0110, 0b1110, 0b1111}};
116 for (const auto &[Feat, EncodedVal] : llvm::zip(t: Decoded, u: Encoded))
117 EXPECT_EQ(Feat.encode(), EncodedVal);
118 for (const auto &[Feat, EncodedVal] : llvm::zip(t: Decoded, u: Encoded)) {
119 Expected<BBAddrMap::Features> FeatEnableOrError =
120 BBAddrMap::Features::decode(Val: EncodedVal);
121 ASSERT_THAT_EXPECTED(FeatEnableOrError, Succeeded());
122 EXPECT_EQ(*FeatEnableOrError, Feat);
123 }
124}
125
126TEST(ELFTypesTest, BBAddrMapFeaturesInvalidEncodingTest) {
127 const std::array<std::string, 2> Errors = {
128 "invalid encoding for BBAddrMap::Features: 0x10",
129 "invalid encoding for BBAddrMap::Features: 0xff"};
130 const std::array<uint8_t, 2> Values = {._M_elems: {0b10000, 0b1111'1111}};
131 for (const auto &[Val, Error] : llvm::zip(t: Values, u: Errors)) {
132 EXPECT_THAT_ERROR(BBAddrMap::Features::decode(Val).takeError(),
133 FailedWithMessage(Error));
134 }
135}
136

source code of llvm/unittests/Object/ELFTypesTest.cpp